libsmb: Centralize the SMB2 protocol check
[Samba.git] / libcli / cldap / cldap.c
blob7de72b5e8996d424023a52186afd5fa995f4262e
1 /*
2 Unix SMB/CIFS implementation.
4 cldap client library
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Stefan Metzmacher 2009
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 see RFC1798 for details of CLDAP
26 basic properties
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
35 #include "includes.h"
36 #include <tevent.h>
37 #include "../lib/util/dlinklist.h"
38 #include "../libcli/ldap/ldap_message.h"
39 #include "../libcli/ldap/ldap_ndr.h"
40 #include "../libcli/cldap/cldap.h"
41 #include "../lib/tsocket/tsocket.h"
42 #include "../libcli/security/dom_sid.h"
43 #include "../librpc/gen_ndr/ndr_nbt.h"
44 #include "../lib/util/asn1.h"
45 #include "../lib/util/tevent_ntstatus.h"
47 #undef strcasecmp
50 context structure for operations on cldap packets
52 struct cldap_socket {
53 /* the low level socket */
54 struct tdgram_context *sock;
57 * Are we in connected mode, which means
58 * we get ICMP errors back instead of timing
59 * out requests. And we can only send requests
60 * to the connected peer.
62 bool connected;
64 /* the queue for outgoing dgrams */
65 struct tevent_queue *send_queue;
67 /* do we have an async tsocket_recvfrom request pending */
68 struct tevent_req *recv_subreq;
70 struct {
71 /* a queue of pending search requests */
72 struct cldap_search_state *list;
74 /* mapping from message_id to pending request */
75 struct idr_context *idr;
76 } searches;
78 /* what to do with incoming request packets */
79 struct {
80 struct tevent_context *ev;
81 void (*handler)(struct cldap_socket *,
82 void *private_data,
83 struct cldap_incoming *);
84 void *private_data;
85 } incoming;
88 struct cldap_search_state {
89 struct cldap_search_state *prev, *next;
91 struct {
92 struct tevent_context *ev;
93 struct cldap_socket *cldap;
94 } caller;
96 int message_id;
98 struct {
99 uint32_t idx;
100 uint32_t delay;
101 uint32_t count;
102 struct tsocket_address *dest;
103 DATA_BLOB blob;
104 } request;
106 struct {
107 struct cldap_incoming *in;
108 struct asn1_data *asn1;
109 } response;
111 struct tevent_req *req;
115 * For CLDAP we limit the maximum search request size to 4kb
117 #define MAX_SEARCH_REQUEST 4096
119 static int cldap_socket_destructor(struct cldap_socket *c)
121 while (c->searches.list) {
122 struct cldap_search_state *s = c->searches.list;
123 DLIST_REMOVE(c->searches.list, s);
124 ZERO_STRUCT(s->caller);
127 talloc_free(c->recv_subreq);
128 talloc_free(c->send_queue);
129 talloc_free(c->sock);
130 return 0;
133 static void cldap_recvfrom_done(struct tevent_req *subreq);
135 static bool cldap_recvfrom_setup(struct cldap_socket *c)
137 struct tevent_context *ev;
139 if (c->recv_subreq) {
140 return true;
143 if (!c->searches.list && !c->incoming.handler) {
144 return true;
147 ev = c->incoming.ev;
148 if (ev == NULL) {
149 /* this shouldn't happen but should be protected against */
150 if (c->searches.list == NULL) {
151 return false;
153 ev = c->searches.list->caller.ev;
156 c->recv_subreq = tdgram_recvfrom_send(c, ev, c->sock);
157 if (!c->recv_subreq) {
158 return false;
160 tevent_req_set_callback(c->recv_subreq, cldap_recvfrom_done, c);
162 return true;
165 static void cldap_recvfrom_stop(struct cldap_socket *c)
167 if (!c->recv_subreq) {
168 return;
171 if (c->searches.list || c->incoming.handler) {
172 return;
175 talloc_free(c->recv_subreq);
176 c->recv_subreq = NULL;
179 static bool cldap_socket_recv_dgram(struct cldap_socket *c,
180 struct cldap_incoming *in);
182 static void cldap_recvfrom_done(struct tevent_req *subreq)
184 struct cldap_socket *c = tevent_req_callback_data(subreq,
185 struct cldap_socket);
186 struct cldap_incoming *in = NULL;
187 ssize_t ret;
188 bool setup_done;
190 c->recv_subreq = NULL;
192 in = talloc_zero(c, struct cldap_incoming);
193 if (!in) {
194 goto nomem;
197 ret = tdgram_recvfrom_recv(subreq,
198 &in->recv_errno,
200 &in->buf,
201 &in->src);
202 talloc_free(subreq);
203 subreq = NULL;
204 if (ret >= 0) {
205 in->len = ret;
207 if (ret == -1 && in->recv_errno == 0) {
208 in->recv_errno = EIO;
211 /* this function should free or steal 'in' */
212 setup_done = cldap_socket_recv_dgram(c, in);
213 in = NULL;
215 if (!setup_done && !cldap_recvfrom_setup(c)) {
216 goto nomem;
219 return;
221 nomem:
222 talloc_free(subreq);
223 talloc_free(in);
227 handle recv events on a cldap socket
229 static bool cldap_socket_recv_dgram(struct cldap_socket *c,
230 struct cldap_incoming *in)
232 struct asn1_data *asn1;
233 void *p;
234 struct cldap_search_state *search;
235 NTSTATUS status;
236 struct ldap_request_limits limits = {
237 .max_search_size = MAX_SEARCH_REQUEST
240 if (in->recv_errno != 0) {
241 goto error;
244 asn1 = asn1_init(in, ASN1_MAX_TREE_DEPTH);
245 if (!asn1) {
246 goto nomem;
249 asn1_load_nocopy(asn1, in->buf, in->len);
251 in->ldap_msg = talloc(in, struct ldap_message);
252 if (in->ldap_msg == NULL) {
253 goto nomem;
256 /* this initial decode is used to find the message id */
257 status = ldap_decode(asn1, &limits, NULL, in->ldap_msg);
258 if (!NT_STATUS_IS_OK(status)) {
259 goto nterror;
262 /* find the pending request */
263 p = idr_find(c->searches.idr, in->ldap_msg->messageid);
264 if (p == NULL) {
265 if (!c->incoming.handler) {
266 TALLOC_FREE(in);
267 return true;
270 /* this function should free or steal 'in' */
271 c->incoming.handler(c, c->incoming.private_data, in);
272 return false;
275 search = talloc_get_type_abort(p, struct cldap_search_state);
276 search->response.in = talloc_move(search, &in);
278 search->response.asn1 = asn1;
280 asn1_load_nocopy(search->response.asn1,
281 search->response.in->buf, search->response.in->len);
283 DLIST_REMOVE(c->searches.list, search);
285 if (cldap_recvfrom_setup(c)) {
286 tevent_req_done(search->req);
287 return true;
291 * This request was ok, just defer the notify of the caller
292 * and then just fail the next request if needed
294 tevent_req_defer_callback(search->req, search->caller.ev);
295 tevent_req_done(search->req);
297 status = NT_STATUS_NO_MEMORY;
298 /* in is NULL it this point */
299 goto nterror;
300 nomem:
301 in->recv_errno = ENOMEM;
302 error:
303 status = map_nt_error_from_unix_common(in->recv_errno);
304 nterror:
305 TALLOC_FREE(in);
306 /* in connected mode the first pending search gets the error */
307 if (!c->connected) {
308 /* otherwise we just ignore the error */
309 return false;
311 if (!c->searches.list) {
312 return false;
315 * We might called tevent_req_done() for a successful
316 * search before, so we better deliver the failure
317 * after the success, that is why we better also
318 * use tevent_req_defer_callback() here.
320 tevent_req_defer_callback(c->searches.list->req,
321 c->searches.list->caller.ev);
322 tevent_req_nterror(c->searches.list->req, status);
323 return false;
327 initialise a cldap_sock
329 NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
330 const struct tsocket_address *local_addr,
331 const struct tsocket_address *remote_addr,
332 struct cldap_socket **_cldap)
334 struct cldap_socket *c = NULL;
335 struct tsocket_address *any = NULL;
336 NTSTATUS status;
337 int ret;
338 const char *fam = NULL;
340 if (local_addr == NULL && remote_addr == NULL) {
341 return NT_STATUS_INVALID_PARAMETER_MIX;
344 if (remote_addr) {
345 bool is_ipv4;
346 bool is_ipv6;
348 is_ipv4 = tsocket_address_is_inet(remote_addr, "ipv4");
349 is_ipv6 = tsocket_address_is_inet(remote_addr, "ipv6");
351 if (is_ipv4) {
352 fam = "ipv4";
353 } else if (is_ipv6) {
354 fam = "ipv6";
355 } else {
356 return NT_STATUS_INVALID_ADDRESS;
360 c = talloc_zero(mem_ctx, struct cldap_socket);
361 if (!c) {
362 goto nomem;
365 if (!local_addr) {
367 * Here we know the address family of the remote address.
369 if (fam == NULL) {
370 return NT_STATUS_INVALID_PARAMETER_MIX;
373 ret = tsocket_address_inet_from_strings(c, fam,
374 NULL, 0,
375 &any);
376 if (ret != 0) {
377 status = map_nt_error_from_unix_common(errno);
378 goto nterror;
380 local_addr = any;
383 c->searches.idr = idr_init(c);
384 if (!c->searches.idr) {
385 goto nomem;
388 ret = tdgram_inet_udp_socket(local_addr, remote_addr,
389 c, &c->sock);
390 if (ret != 0) {
391 status = map_nt_error_from_unix_common(errno);
392 goto nterror;
394 talloc_free(any);
396 if (remote_addr) {
397 c->connected = true;
400 c->send_queue = tevent_queue_create(c, "cldap_send_queue");
401 if (!c->send_queue) {
402 goto nomem;
405 talloc_set_destructor(c, cldap_socket_destructor);
407 *_cldap = c;
408 return NT_STATUS_OK;
410 nomem:
411 status = NT_STATUS_NO_MEMORY;
412 nterror:
413 talloc_free(c);
414 return status;
418 setup a handler for incoming requests
420 NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
421 struct tevent_context *ev,
422 void (*handler)(struct cldap_socket *,
423 void *private_data,
424 struct cldap_incoming *),
425 void *private_data)
427 if (c->connected) {
428 return NT_STATUS_PIPE_CONNECTED;
431 c->incoming.ev = ev;
432 c->incoming.handler = handler;
433 c->incoming.private_data = private_data;
435 if (!cldap_recvfrom_setup(c)) {
436 ZERO_STRUCT(c->incoming);
437 return NT_STATUS_NO_MEMORY;
440 return NT_STATUS_OK;
443 struct cldap_reply_state {
444 struct tsocket_address *dest;
445 DATA_BLOB blob;
448 static void cldap_reply_state_destroy(struct tevent_req *subreq);
451 queue a cldap reply for send
453 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
455 struct cldap_reply_state *state = NULL;
456 struct ldap_message *msg;
457 DATA_BLOB blob1, blob2;
458 NTSTATUS status;
459 struct tevent_req *subreq;
461 if (cldap->connected) {
462 return NT_STATUS_PIPE_CONNECTED;
465 if (cldap->incoming.ev == NULL) {
466 return NT_STATUS_INVALID_PIPE_STATE;
469 if (!io->dest) {
470 return NT_STATUS_INVALID_ADDRESS;
473 state = talloc(cldap, struct cldap_reply_state);
474 NT_STATUS_HAVE_NO_MEMORY(state);
476 state->dest = tsocket_address_copy(io->dest, state);
477 if (!state->dest) {
478 goto nomem;
481 msg = talloc(state, struct ldap_message);
482 if (!msg) {
483 goto nomem;
486 msg->messageid = io->messageid;
487 msg->controls = NULL;
489 if (io->response) {
490 msg->type = LDAP_TAG_SearchResultEntry;
491 msg->r.SearchResultEntry = *io->response;
493 if (!ldap_encode(msg, NULL, &blob1, state)) {
494 status = NT_STATUS_INVALID_PARAMETER;
495 goto failed;
497 } else {
498 blob1 = data_blob(NULL, 0);
501 msg->type = LDAP_TAG_SearchResultDone;
502 msg->r.SearchResultDone = *io->result;
504 if (!ldap_encode(msg, NULL, &blob2, state)) {
505 status = NT_STATUS_INVALID_PARAMETER;
506 goto failed;
508 talloc_free(msg);
510 state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
511 if (!state->blob.data) {
512 goto nomem;
515 memcpy(state->blob.data, blob1.data, blob1.length);
516 memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
517 data_blob_free(&blob1);
518 data_blob_free(&blob2);
520 subreq = tdgram_sendto_queue_send(state,
521 cldap->incoming.ev,
522 cldap->sock,
523 cldap->send_queue,
524 state->blob.data,
525 state->blob.length,
526 state->dest);
527 if (!subreq) {
528 goto nomem;
530 /* the callback will just free the state, as we don't need a result */
531 tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
533 return NT_STATUS_OK;
535 nomem:
536 status = NT_STATUS_NO_MEMORY;
537 failed:
538 talloc_free(state);
539 return status;
542 static void cldap_reply_state_destroy(struct tevent_req *subreq)
544 struct cldap_reply_state *state = tevent_req_callback_data(subreq,
545 struct cldap_reply_state);
547 /* we don't want to know the result here, we just free the state */
548 talloc_free(subreq);
549 talloc_free(state);
552 static int cldap_search_state_destructor(struct cldap_search_state *s)
554 if (s->caller.cldap) {
555 if (s->message_id != -1) {
556 idr_remove(s->caller.cldap->searches.idr, s->message_id);
557 s->message_id = -1;
559 DLIST_REMOVE(s->caller.cldap->searches.list, s);
560 cldap_recvfrom_stop(s->caller.cldap);
561 ZERO_STRUCT(s->caller);
564 return 0;
567 static void cldap_search_state_queue_done(struct tevent_req *subreq);
568 static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
571 queue a cldap reply for send
573 struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
574 struct tevent_context *ev,
575 struct cldap_socket *cldap,
576 const struct cldap_search *io)
578 struct tevent_req *req, *subreq;
579 struct cldap_search_state *state = NULL;
580 struct ldap_message *msg;
581 struct ldap_SearchRequest *search;
582 struct timeval now;
583 struct timeval end;
584 uint32_t i;
585 int ret;
587 req = tevent_req_create(mem_ctx, &state,
588 struct cldap_search_state);
589 if (!req) {
590 return NULL;
592 state->caller.ev = ev;
593 state->req = req;
594 state->caller.cldap = cldap;
595 state->message_id = -1;
597 talloc_set_destructor(state, cldap_search_state_destructor);
599 if (state->caller.cldap == NULL) {
600 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
601 goto post;
604 if (io->in.dest_address) {
605 if (cldap->connected) {
606 tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
607 goto post;
609 ret = tsocket_address_inet_from_strings(state,
610 "ip",
611 io->in.dest_address,
612 io->in.dest_port,
613 &state->request.dest);
614 if (ret != 0) {
615 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
616 goto post;
618 } else {
619 if (!cldap->connected) {
620 tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
621 goto post;
623 state->request.dest = NULL;
626 state->message_id = idr_get_new_random(cldap->searches.idr,
627 state, UINT16_MAX);
628 if (state->message_id == -1) {
629 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
630 goto post;
633 msg = talloc(state, struct ldap_message);
634 if (tevent_req_nomem(msg, req)) {
635 goto post;
638 msg->messageid = state->message_id;
639 msg->type = LDAP_TAG_SearchRequest;
640 msg->controls = NULL;
641 search = &msg->r.SearchRequest;
643 search->basedn = "";
644 search->scope = LDAP_SEARCH_SCOPE_BASE;
645 search->deref = LDAP_DEREFERENCE_NEVER;
646 search->timelimit = 0;
647 search->sizelimit = 0;
648 search->attributesonly = false;
649 search->num_attributes = str_list_length(io->in.attributes);
650 search->attributes = io->in.attributes;
651 search->tree = ldb_parse_tree(msg, io->in.filter);
652 if (tevent_req_nomem(search->tree, req)) {
653 goto post;
656 if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
657 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
658 goto post;
660 talloc_free(msg);
662 state->request.idx = 0;
663 state->request.delay = 10*1000*1000;
664 state->request.count = 3;
665 if (io->in.timeout > 0) {
666 state->request.delay = io->in.timeout * 1000 * 1000;
667 state->request.count = io->in.retries + 1;
670 now = tevent_timeval_current();
671 end = now;
672 for (i = 0; i < state->request.count; i++) {
673 end = tevent_timeval_add(&end, state->request.delay / 1000000,
674 state->request.delay % 1000000);
677 if (!tevent_req_set_endtime(req, state->caller.ev, end)) {
678 goto post;
681 subreq = tdgram_sendto_queue_send(state,
682 state->caller.ev,
683 state->caller.cldap->sock,
684 state->caller.cldap->send_queue,
685 state->request.blob.data,
686 state->request.blob.length,
687 state->request.dest);
688 if (tevent_req_nomem(subreq, req)) {
689 goto post;
691 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
693 DLIST_ADD_END(cldap->searches.list, state);
695 return req;
697 post:
698 return tevent_req_post(req, state->caller.ev);
701 static void cldap_search_state_queue_done(struct tevent_req *subreq)
703 struct tevent_req *req = tevent_req_callback_data(subreq,
704 struct tevent_req);
705 struct cldap_search_state *state = tevent_req_data(req,
706 struct cldap_search_state);
707 ssize_t ret;
708 int sys_errno = 0;
709 struct timeval next;
711 ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
712 talloc_free(subreq);
713 if (ret == -1) {
714 NTSTATUS status;
715 status = map_nt_error_from_unix_common(sys_errno);
716 DLIST_REMOVE(state->caller.cldap->searches.list, state);
717 ZERO_STRUCT(state->caller.cldap);
718 tevent_req_nterror(req, status);
719 return;
722 state->request.idx++;
724 /* wait for incoming traffic */
725 if (!cldap_recvfrom_setup(state->caller.cldap)) {
726 tevent_req_oom(req);
727 return;
730 if (state->request.idx > state->request.count) {
731 /* we just wait for the response or a timeout */
732 return;
735 next = tevent_timeval_current_ofs(state->request.delay / 1000000,
736 state->request.delay % 1000000);
737 subreq = tevent_wakeup_send(state,
738 state->caller.ev,
739 next);
740 if (tevent_req_nomem(subreq, req)) {
741 return;
743 tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
746 static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
748 struct tevent_req *req = tevent_req_callback_data(subreq,
749 struct tevent_req);
750 struct cldap_search_state *state = tevent_req_data(req,
751 struct cldap_search_state);
752 bool ok;
754 ok = tevent_wakeup_recv(subreq);
755 talloc_free(subreq);
756 if (!ok) {
757 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
758 return;
761 subreq = tdgram_sendto_queue_send(state,
762 state->caller.ev,
763 state->caller.cldap->sock,
764 state->caller.cldap->send_queue,
765 state->request.blob.data,
766 state->request.blob.length,
767 state->request.dest);
768 if (tevent_req_nomem(subreq, req)) {
769 return;
771 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
775 receive a cldap reply
777 NTSTATUS cldap_search_recv(struct tevent_req *req,
778 TALLOC_CTX *mem_ctx,
779 struct cldap_search *io)
781 struct cldap_search_state *state = tevent_req_data(req,
782 struct cldap_search_state);
783 struct ldap_message *ldap_msg;
784 NTSTATUS status;
785 struct ldap_request_limits limits = {
786 .max_search_size = MAX_SEARCH_REQUEST
789 if (tevent_req_is_nterror(req, &status)) {
790 goto failed;
793 ldap_msg = talloc(mem_ctx, struct ldap_message);
794 if (!ldap_msg) {
795 goto nomem;
798 status = ldap_decode(state->response.asn1, &limits, NULL, ldap_msg);
799 if (!NT_STATUS_IS_OK(status)) {
800 goto failed;
803 ZERO_STRUCT(io->out);
805 /* the first possible form has a search result in first place */
806 if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
807 io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
808 if (!io->out.response) {
809 goto nomem;
811 *io->out.response = ldap_msg->r.SearchResultEntry;
813 /* decode the 2nd part */
814 status = ldap_decode(
815 state->response.asn1, &limits, NULL, ldap_msg);
816 if (!NT_STATUS_IS_OK(status)) {
817 goto failed;
821 if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
822 status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
823 goto failed;
826 io->out.result = talloc(mem_ctx, struct ldap_Result);
827 if (!io->out.result) {
828 goto nomem;
830 *io->out.result = ldap_msg->r.SearchResultDone;
832 if (io->out.result->resultcode != LDAP_SUCCESS) {
833 status = NT_STATUS_LDAP(io->out.result->resultcode);
834 goto failed;
837 tevent_req_received(req);
838 return NT_STATUS_OK;
840 nomem:
841 status = NT_STATUS_NO_MEMORY;
842 failed:
843 tevent_req_received(req);
844 return status;
849 synchronous cldap search
851 NTSTATUS cldap_search(struct cldap_socket *cldap,
852 TALLOC_CTX *mem_ctx,
853 struct cldap_search *io)
855 TALLOC_CTX *frame;
856 struct tevent_req *req;
857 struct tevent_context *ev;
858 NTSTATUS status;
860 if (cldap->searches.list) {
861 return NT_STATUS_PIPE_BUSY;
864 if (cldap->incoming.handler) {
865 return NT_STATUS_INVALID_PIPE_STATE;
868 frame = talloc_stackframe();
870 ev = samba_tevent_context_init(frame);
871 if (ev == NULL) {
872 TALLOC_FREE(frame);
873 return NT_STATUS_NO_MEMORY;
876 req = cldap_search_send(mem_ctx, ev, cldap, io);
877 if (req == NULL) {
878 TALLOC_FREE(frame);
879 return NT_STATUS_NO_MEMORY;
882 if (!tevent_req_poll(req, ev)) {
883 status = map_nt_error_from_unix_common(errno);
884 TALLOC_FREE(frame);
885 return status;
888 status = cldap_search_recv(req, mem_ctx, io);
889 if (!NT_STATUS_IS_OK(status)) {
890 TALLOC_FREE(frame);
891 return status;
894 TALLOC_FREE(frame);
895 return NT_STATUS_OK;
898 struct cldap_netlogon_state {
899 struct cldap_search search;
902 char *cldap_netlogon_create_filter(TALLOC_CTX *mem_ctx,
903 const struct cldap_netlogon *io)
905 char *filter;
907 filter = talloc_asprintf(mem_ctx, "(&(NtVer=%s)",
908 ldap_encode_ndr_uint32(mem_ctx, io->in.version));
909 if (filter == NULL)
910 return NULL;
912 if (io->in.user) {
913 filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
914 if (filter == NULL) {
915 return NULL;
918 if (io->in.host) {
919 filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
920 if (filter == NULL) {
921 return NULL;
924 if (io->in.realm) {
925 filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
926 if (filter == NULL) {
927 return NULL;
930 if (io->in.acct_control != -1) {
931 filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)",
932 ldap_encode_ndr_uint32(mem_ctx, io->in.acct_control));
933 if (filter == NULL) {
934 return NULL;
937 if (io->in.domain_sid) {
938 struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, io->in.domain_sid);
940 filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
941 ldap_encode_ndr_dom_sid(mem_ctx, sid));
942 if (filter == NULL) {
943 return NULL;
946 if (io->in.domain_guid) {
947 struct GUID guid;
948 GUID_from_string(io->in.domain_guid, &guid);
950 filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
951 ldap_encode_ndr_GUID(mem_ctx, &guid));
952 if (filter == NULL) {
953 return NULL;
956 filter = talloc_asprintf_append_buffer(filter, ")");
958 return filter;
961 static void cldap_netlogon_state_done(struct tevent_req *subreq);
963 queue a cldap netlogon for send
965 struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
966 struct tevent_context *ev,
967 struct cldap_socket *cldap,
968 const struct cldap_netlogon *io)
970 struct tevent_req *req, *subreq;
971 struct cldap_netlogon_state *state;
972 char *filter;
973 static const char * const attr[] = { "NetLogon", NULL };
975 req = tevent_req_create(mem_ctx, &state,
976 struct cldap_netlogon_state);
977 if (!req) {
978 return NULL;
981 filter = cldap_netlogon_create_filter(state, io);
982 if (tevent_req_nomem(filter, req)) {
983 goto post;
986 if (io->in.dest_address) {
987 state->search.in.dest_address = talloc_strdup(state,
988 io->in.dest_address);
989 if (tevent_req_nomem(state->search.in.dest_address, req)) {
990 goto post;
992 state->search.in.dest_port = io->in.dest_port;
993 } else {
994 state->search.in.dest_address = NULL;
995 state->search.in.dest_port = 0;
997 state->search.in.filter = filter;
998 state->search.in.attributes = attr;
999 state->search.in.timeout = 2;
1000 state->search.in.retries = 2;
1002 subreq = cldap_search_send(state, ev, cldap, &state->search);
1003 if (tevent_req_nomem(subreq, req)) {
1004 goto post;
1006 tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
1008 return req;
1009 post:
1010 return tevent_req_post(req, ev);
1013 static void cldap_netlogon_state_done(struct tevent_req *subreq)
1015 struct tevent_req *req = tevent_req_callback_data(subreq,
1016 struct tevent_req);
1017 struct cldap_netlogon_state *state = tevent_req_data(req,
1018 struct cldap_netlogon_state);
1019 NTSTATUS status;
1021 status = cldap_search_recv(subreq, state, &state->search);
1022 talloc_free(subreq);
1024 if (tevent_req_nterror(req, status)) {
1025 return;
1028 tevent_req_done(req);
1032 receive a cldap netlogon reply
1034 NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
1035 TALLOC_CTX *mem_ctx,
1036 struct cldap_netlogon *io)
1038 struct cldap_netlogon_state *state = tevent_req_data(req,
1039 struct cldap_netlogon_state);
1040 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1041 DATA_BLOB *data;
1043 if (tevent_req_is_nterror(req, &status)) {
1044 goto failed;
1047 if (state->search.out.response == NULL) {
1048 status = NT_STATUS_NOT_FOUND;
1049 goto failed;
1052 if (state->search.out.response->num_attributes != 1 ||
1053 strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
1054 state->search.out.response->attributes[0].num_values != 1 ||
1055 state->search.out.response->attributes[0].values->length < 2) {
1056 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1057 goto failed;
1059 data = state->search.out.response->attributes[0].values;
1061 status = pull_netlogon_samlogon_response(data, mem_ctx,
1062 &io->out.netlogon);
1063 if (!NT_STATUS_IS_OK(status)) {
1064 goto failed;
1067 if (io->in.map_response) {
1068 map_netlogon_samlogon_response(&io->out.netlogon);
1071 status = NT_STATUS_OK;
1072 failed:
1073 tevent_req_received(req);
1074 return status;
1078 sync cldap netlogon search
1080 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
1081 TALLOC_CTX *mem_ctx,
1082 struct cldap_netlogon *io)
1084 TALLOC_CTX *frame;
1085 struct tevent_req *req;
1086 struct tevent_context *ev;
1087 NTSTATUS status;
1089 if (cldap->searches.list) {
1090 return NT_STATUS_PIPE_BUSY;
1093 if (cldap->incoming.handler) {
1094 return NT_STATUS_INVALID_PIPE_STATE;
1097 frame = talloc_stackframe();
1099 ev = samba_tevent_context_init(frame);
1100 if (ev == NULL) {
1101 TALLOC_FREE(frame);
1102 return NT_STATUS_NO_MEMORY;
1105 req = cldap_netlogon_send(mem_ctx, ev, cldap, io);
1106 if (req == NULL) {
1107 TALLOC_FREE(frame);
1108 return NT_STATUS_NO_MEMORY;
1111 if (!tevent_req_poll(req, ev)) {
1112 status = map_nt_error_from_unix_common(errno);
1113 TALLOC_FREE(frame);
1114 return status;
1117 status = cldap_netlogon_recv(req, mem_ctx, io);
1118 if (!NT_STATUS_IS_OK(status)) {
1119 TALLOC_FREE(frame);
1120 return status;
1123 TALLOC_FREE(frame);
1124 return NT_STATUS_OK;
1129 send an empty reply (used on any error, so the client doesn't keep waiting
1130 or send the bad request again)
1132 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1133 uint32_t message_id,
1134 struct tsocket_address *dest)
1136 NTSTATUS status;
1137 struct cldap_reply reply;
1138 struct ldap_Result result;
1140 reply.messageid = message_id;
1141 reply.dest = dest;
1142 reply.response = NULL;
1143 reply.result = &result;
1145 ZERO_STRUCT(result);
1147 status = cldap_reply_send(cldap, &reply);
1149 return status;
1153 send an error reply (used on any error, so the client doesn't keep waiting
1154 or send the bad request again)
1156 NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
1157 uint32_t message_id,
1158 struct tsocket_address *dest,
1159 int resultcode,
1160 const char *errormessage)
1162 NTSTATUS status;
1163 struct cldap_reply reply;
1164 struct ldap_Result result;
1166 reply.messageid = message_id;
1167 reply.dest = dest;
1168 reply.response = NULL;
1169 reply.result = &result;
1171 ZERO_STRUCT(result);
1172 result.resultcode = resultcode;
1173 result.errormessage = errormessage;
1175 status = cldap_reply_send(cldap, &reply);
1177 return status;
1182 send a netlogon reply
1184 NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
1185 uint32_t message_id,
1186 struct tsocket_address *dest,
1187 uint32_t version,
1188 struct netlogon_samlogon_response *netlogon)
1190 NTSTATUS status;
1191 struct cldap_reply reply;
1192 struct ldap_SearchResEntry response;
1193 struct ldap_Result result;
1194 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
1195 DATA_BLOB blob;
1197 status = push_netlogon_samlogon_response(&blob, tmp_ctx,
1198 netlogon);
1199 if (!NT_STATUS_IS_OK(status)) {
1200 talloc_free(tmp_ctx);
1201 return status;
1203 reply.messageid = message_id;
1204 reply.dest = dest;
1205 reply.response = &response;
1206 reply.result = &result;
1208 ZERO_STRUCT(result);
1210 response.dn = "";
1211 response.num_attributes = 1;
1212 response.attributes = talloc(tmp_ctx, struct ldb_message_element);
1213 NT_STATUS_HAVE_NO_MEMORY(response.attributes);
1214 response.attributes->name = "netlogon";
1215 response.attributes->num_values = 1;
1216 response.attributes->values = &blob;
1218 status = cldap_reply_send(cldap, &reply);
1220 talloc_free(tmp_ctx);
1222 return status;