Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : cldap client library
5 :
6 : Copyright (C) Andrew Tridgell 2005
7 : Copyright (C) Stefan Metzmacher 2009
8 :
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.
13 :
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.
18 :
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/>.
21 : */
22 :
23 : /*
24 : see RFC1798 for details of CLDAP
25 :
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
33 : */
34 :
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"
46 : #include "lib/util/idtree_random.h"
47 :
48 : #undef strcasecmp
49 :
50 : /*
51 : context structure for operations on cldap packets
52 : */
53 : struct cldap_socket {
54 : /* the low level socket */
55 : struct tdgram_context *sock;
56 :
57 : /*
58 : * Are we in connected mode, which means
59 : * we get ICMP errors back instead of timing
60 : * out requests. And we can only send requests
61 : * to the connected peer.
62 : */
63 : bool connected;
64 :
65 : /* the queue for outgoing dgrams */
66 : struct tevent_queue *send_queue;
67 :
68 : /* do we have an async tsocket_recvfrom request pending */
69 : struct tevent_req *recv_subreq;
70 :
71 : struct {
72 : /* a queue of pending search requests */
73 : struct cldap_search_state *list;
74 :
75 : /* mapping from message_id to pending request */
76 : struct idr_context *idr;
77 : } searches;
78 :
79 : /* what to do with incoming request packets */
80 : struct {
81 : struct tevent_context *ev;
82 : void (*handler)(struct cldap_socket *,
83 : void *private_data,
84 : struct cldap_incoming *);
85 : void *private_data;
86 : } incoming;
87 : };
88 :
89 : struct cldap_search_state {
90 : struct cldap_search_state *prev, *next;
91 :
92 : struct {
93 : struct tevent_context *ev;
94 : struct cldap_socket *cldap;
95 : } caller;
96 :
97 : int message_id;
98 :
99 : struct {
100 : uint32_t idx;
101 : uint32_t delay;
102 : uint32_t count;
103 : struct tsocket_address *dest;
104 : DATA_BLOB blob;
105 : } request;
106 :
107 : struct {
108 : struct cldap_incoming *in;
109 : struct asn1_data *asn1;
110 : } response;
111 :
112 : struct tevent_req *req;
113 : };
114 :
115 : /*
116 : * For CLDAP we limit the maximum search request size to 4kb
117 : */
118 : #define MAX_SEARCH_REQUEST 4096
119 :
120 979 : static int cldap_socket_destructor(struct cldap_socket *c)
121 : {
122 979 : while (c->searches.list) {
123 0 : struct cldap_search_state *s = c->searches.list;
124 0 : DLIST_REMOVE(c->searches.list, s);
125 0 : ZERO_STRUCT(s->caller);
126 : }
127 :
128 979 : talloc_free(c->recv_subreq);
129 979 : talloc_free(c->send_queue);
130 979 : talloc_free(c->sock);
131 979 : return 0;
132 : }
133 :
134 : static void cldap_recvfrom_done(struct tevent_req *subreq);
135 :
136 3633 : static bool cldap_recvfrom_setup(struct cldap_socket *c)
137 : {
138 : struct tevent_context *ev;
139 :
140 3633 : if (c->recv_subreq) {
141 0 : return true;
142 : }
143 :
144 3633 : if (!c->searches.list && !c->incoming.handler) {
145 1082 : return true;
146 : }
147 :
148 2551 : ev = c->incoming.ev;
149 2551 : if (ev == NULL) {
150 : /* this shouldn't happen but should be protected against */
151 1082 : if (c->searches.list == NULL) {
152 0 : return false;
153 : }
154 1082 : ev = c->searches.list->caller.ev;
155 : }
156 :
157 2551 : c->recv_subreq = tdgram_recvfrom_send(c, ev, c->sock);
158 2551 : if (!c->recv_subreq) {
159 0 : return false;
160 : }
161 2551 : tevent_req_set_callback(c->recv_subreq, cldap_recvfrom_done, c);
162 :
163 2551 : return true;
164 : }
165 :
166 1082 : static void cldap_recvfrom_stop(struct cldap_socket *c)
167 : {
168 1082 : if (!c->recv_subreq) {
169 1082 : return;
170 : }
171 :
172 0 : if (c->searches.list || c->incoming.handler) {
173 0 : return;
174 : }
175 :
176 0 : talloc_free(c->recv_subreq);
177 0 : c->recv_subreq = NULL;
178 : }
179 :
180 : static bool cldap_socket_recv_dgram(struct cldap_socket *c,
181 : struct cldap_incoming *in);
182 :
183 2355 : static void cldap_recvfrom_done(struct tevent_req *subreq)
184 : {
185 2355 : struct cldap_socket *c = tevent_req_callback_data(subreq,
186 : struct cldap_socket);
187 2355 : struct cldap_incoming *in = NULL;
188 : ssize_t ret;
189 : bool setup_done;
190 :
191 2355 : c->recv_subreq = NULL;
192 :
193 2355 : in = talloc_zero(c, struct cldap_incoming);
194 2355 : if (!in) {
195 0 : goto nomem;
196 : }
197 :
198 2355 : ret = tdgram_recvfrom_recv(subreq,
199 : &in->recv_errno,
200 : in,
201 : &in->buf,
202 : &in->src);
203 2355 : talloc_free(subreq);
204 2355 : subreq = NULL;
205 2355 : if (ret >= 0) {
206 2355 : in->len = ret;
207 : }
208 2355 : if (ret == -1 && in->recv_errno == 0) {
209 0 : in->recv_errno = EIO;
210 : }
211 :
212 : /* this function should free or steal 'in' */
213 2355 : setup_done = cldap_socket_recv_dgram(c, in);
214 2355 : in = NULL;
215 :
216 2355 : if (!setup_done && !cldap_recvfrom_setup(c)) {
217 0 : goto nomem;
218 : }
219 :
220 2355 : return;
221 :
222 0 : nomem:
223 0 : talloc_free(subreq);
224 0 : talloc_free(in);
225 : }
226 :
227 : /*
228 : handle recv events on a cldap socket
229 : */
230 2355 : static bool cldap_socket_recv_dgram(struct cldap_socket *c,
231 : struct cldap_incoming *in)
232 : {
233 : struct asn1_data *asn1;
234 : void *p;
235 : struct cldap_search_state *search;
236 : NTSTATUS status;
237 2355 : struct ldap_request_limits limits = {
238 : .max_search_size = MAX_SEARCH_REQUEST
239 : };
240 :
241 2355 : if (in->recv_errno != 0) {
242 0 : goto error;
243 : }
244 :
245 2355 : asn1 = asn1_init(in, ASN1_MAX_TREE_DEPTH);
246 2355 : if (!asn1) {
247 0 : goto nomem;
248 : }
249 :
250 2355 : asn1_load_nocopy(asn1, in->buf, in->len);
251 :
252 2355 : in->ldap_msg = talloc(in, struct ldap_message);
253 2355 : if (in->ldap_msg == NULL) {
254 0 : goto nomem;
255 : }
256 :
257 : /* this initial decode is used to find the message id */
258 2355 : status = ldap_decode(asn1, &limits, NULL, in->ldap_msg);
259 2355 : if (!NT_STATUS_IS_OK(status)) {
260 0 : goto nterror;
261 : }
262 :
263 : /* find the pending request */
264 2355 : p = idr_find(c->searches.idr, in->ldap_msg->messageid);
265 2355 : if (p == NULL) {
266 1273 : if (!c->incoming.handler) {
267 0 : TALLOC_FREE(in);
268 0 : return true;
269 : }
270 :
271 : /* this function should free or steal 'in' */
272 1273 : c->incoming.handler(c, c->incoming.private_data, in);
273 1273 : return false;
274 : }
275 :
276 1082 : search = talloc_get_type_abort(p, struct cldap_search_state);
277 1082 : search->response.in = talloc_move(search, &in);
278 :
279 1082 : search->response.asn1 = asn1;
280 :
281 1082 : asn1_load_nocopy(search->response.asn1,
282 1082 : search->response.in->buf, search->response.in->len);
283 :
284 1082 : DLIST_REMOVE(c->searches.list, search);
285 :
286 1082 : if (cldap_recvfrom_setup(c)) {
287 1082 : tevent_req_done(search->req);
288 1082 : return true;
289 : }
290 :
291 : /*
292 : * This request was ok, just defer the notify of the caller
293 : * and then just fail the next request if needed
294 : */
295 0 : tevent_req_defer_callback(search->req, search->caller.ev);
296 0 : tevent_req_done(search->req);
297 :
298 0 : status = NT_STATUS_NO_MEMORY;
299 : /* in is NULL it this point */
300 0 : goto nterror;
301 0 : nomem:
302 0 : in->recv_errno = ENOMEM;
303 0 : error:
304 0 : status = map_nt_error_from_unix_common(in->recv_errno);
305 0 : nterror:
306 0 : TALLOC_FREE(in);
307 : /* in connected mode the first pending search gets the error */
308 0 : if (!c->connected) {
309 : /* otherwise we just ignore the error */
310 0 : return false;
311 : }
312 0 : if (!c->searches.list) {
313 0 : return false;
314 : }
315 : /*
316 : * We might called tevent_req_done() for a successful
317 : * search before, so we better deliver the failure
318 : * after the success, that is why we better also
319 : * use tevent_req_defer_callback() here.
320 : */
321 0 : tevent_req_defer_callback(c->searches.list->req,
322 0 : c->searches.list->caller.ev);
323 0 : tevent_req_nterror(c->searches.list->req, status);
324 0 : return false;
325 : }
326 :
327 : /*
328 : initialise a cldap_sock
329 : */
330 979 : NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
331 : const struct tsocket_address *local_addr,
332 : const struct tsocket_address *remote_addr,
333 : struct cldap_socket **_cldap)
334 : {
335 979 : struct cldap_socket *c = NULL;
336 979 : struct tsocket_address *any = NULL;
337 : NTSTATUS status;
338 : int ret;
339 979 : const char *fam = NULL;
340 :
341 979 : if (local_addr == NULL && remote_addr == NULL) {
342 0 : return NT_STATUS_INVALID_PARAMETER_MIX;
343 : }
344 :
345 979 : if (remote_addr) {
346 : bool is_ipv4;
347 : bool is_ipv6;
348 :
349 783 : is_ipv4 = tsocket_address_is_inet(remote_addr, "ipv4");
350 783 : is_ipv6 = tsocket_address_is_inet(remote_addr, "ipv6");
351 :
352 783 : if (is_ipv4) {
353 671 : fam = "ipv4";
354 112 : } else if (is_ipv6) {
355 112 : fam = "ipv6";
356 : } else {
357 0 : return NT_STATUS_INVALID_ADDRESS;
358 : }
359 : }
360 :
361 979 : c = talloc_zero(mem_ctx, struct cldap_socket);
362 979 : if (!c) {
363 0 : goto nomem;
364 : }
365 :
366 979 : if (!local_addr) {
367 : /*
368 : * Here we know the address family of the remote address.
369 : */
370 783 : if (fam == NULL) {
371 0 : return NT_STATUS_INVALID_PARAMETER_MIX;
372 : }
373 :
374 783 : ret = tsocket_address_inet_from_strings(c, fam,
375 : NULL, 0,
376 : &any);
377 783 : if (ret != 0) {
378 0 : status = map_nt_error_from_unix_common(errno);
379 0 : goto nterror;
380 : }
381 783 : local_addr = any;
382 : }
383 :
384 979 : c->searches.idr = idr_init(c);
385 979 : if (!c->searches.idr) {
386 0 : goto nomem;
387 : }
388 :
389 979 : ret = tdgram_inet_udp_socket(local_addr, remote_addr,
390 : c, &c->sock);
391 979 : if (ret != 0) {
392 0 : status = map_nt_error_from_unix_common(errno);
393 0 : goto nterror;
394 : }
395 979 : talloc_free(any);
396 :
397 979 : if (remote_addr) {
398 783 : c->connected = true;
399 : }
400 :
401 979 : c->send_queue = tevent_queue_create(c, "cldap_send_queue");
402 979 : if (!c->send_queue) {
403 0 : goto nomem;
404 : }
405 :
406 979 : talloc_set_destructor(c, cldap_socket_destructor);
407 :
408 979 : *_cldap = c;
409 979 : return NT_STATUS_OK;
410 :
411 0 : nomem:
412 0 : status = NT_STATUS_NO_MEMORY;
413 0 : nterror:
414 0 : talloc_free(c);
415 0 : return status;
416 : }
417 :
418 : /*
419 : setup a handler for incoming requests
420 : */
421 196 : NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
422 : struct tevent_context *ev,
423 : void (*handler)(struct cldap_socket *,
424 : void *private_data,
425 : struct cldap_incoming *),
426 : void *private_data)
427 : {
428 196 : if (c->connected) {
429 0 : return NT_STATUS_PIPE_CONNECTED;
430 : }
431 :
432 196 : c->incoming.ev = ev;
433 196 : c->incoming.handler = handler;
434 196 : c->incoming.private_data = private_data;
435 :
436 196 : if (!cldap_recvfrom_setup(c)) {
437 0 : ZERO_STRUCT(c->incoming);
438 0 : return NT_STATUS_NO_MEMORY;
439 : }
440 :
441 196 : return NT_STATUS_OK;
442 : }
443 :
444 : struct cldap_reply_state {
445 : struct tsocket_address *dest;
446 : DATA_BLOB blob;
447 : };
448 :
449 : static void cldap_reply_state_destroy(struct tevent_req *subreq);
450 :
451 : /*
452 : queue a cldap reply for send
453 : */
454 1273 : NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
455 : {
456 1273 : struct cldap_reply_state *state = NULL;
457 : struct ldap_message *msg;
458 : DATA_BLOB blob1, blob2;
459 : NTSTATUS status;
460 : struct tevent_req *subreq;
461 :
462 1273 : if (cldap->connected) {
463 0 : return NT_STATUS_PIPE_CONNECTED;
464 : }
465 :
466 1273 : if (cldap->incoming.ev == NULL) {
467 0 : return NT_STATUS_INVALID_PIPE_STATE;
468 : }
469 :
470 1273 : if (!io->dest) {
471 0 : return NT_STATUS_INVALID_ADDRESS;
472 : }
473 :
474 1273 : state = talloc(cldap, struct cldap_reply_state);
475 1273 : NT_STATUS_HAVE_NO_MEMORY(state);
476 :
477 1273 : state->dest = tsocket_address_copy(io->dest, state);
478 1273 : if (!state->dest) {
479 0 : goto nomem;
480 : }
481 :
482 1273 : msg = talloc(state, struct ldap_message);
483 1273 : if (!msg) {
484 0 : goto nomem;
485 : }
486 :
487 1273 : msg->messageid = io->messageid;
488 1273 : msg->controls = NULL;
489 :
490 1273 : if (io->response) {
491 1267 : msg->type = LDAP_TAG_SearchResultEntry;
492 1267 : msg->r.SearchResultEntry = *io->response;
493 :
494 1267 : if (!ldap_encode(msg, NULL, &blob1, state)) {
495 0 : status = NT_STATUS_INVALID_PARAMETER;
496 0 : goto failed;
497 : }
498 : } else {
499 6 : blob1 = data_blob(NULL, 0);
500 : }
501 :
502 1273 : msg->type = LDAP_TAG_SearchResultDone;
503 1273 : msg->r.SearchResultDone = *io->result;
504 :
505 1273 : if (!ldap_encode(msg, NULL, &blob2, state)) {
506 0 : status = NT_STATUS_INVALID_PARAMETER;
507 0 : goto failed;
508 : }
509 1273 : talloc_free(msg);
510 :
511 1273 : state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
512 1273 : if (!state->blob.data) {
513 0 : goto nomem;
514 : }
515 :
516 1273 : memcpy(state->blob.data, blob1.data, blob1.length);
517 1273 : memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
518 1273 : data_blob_free(&blob1);
519 1273 : data_blob_free(&blob2);
520 :
521 1273 : subreq = tdgram_sendto_queue_send(state,
522 : cldap->incoming.ev,
523 : cldap->sock,
524 : cldap->send_queue,
525 1273 : state->blob.data,
526 : state->blob.length,
527 : state->dest);
528 1273 : if (!subreq) {
529 0 : goto nomem;
530 : }
531 : /* the callback will just free the state, as we don't need a result */
532 1273 : tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
533 :
534 1273 : return NT_STATUS_OK;
535 :
536 0 : nomem:
537 0 : status = NT_STATUS_NO_MEMORY;
538 0 : failed:
539 0 : talloc_free(state);
540 0 : return status;
541 : }
542 :
543 1273 : static void cldap_reply_state_destroy(struct tevent_req *subreq)
544 : {
545 1273 : struct cldap_reply_state *state = tevent_req_callback_data(subreq,
546 : struct cldap_reply_state);
547 :
548 : /* we don't want to know the result here, we just free the state */
549 1273 : talloc_free(subreq);
550 1273 : talloc_free(state);
551 1273 : }
552 :
553 1082 : static int cldap_search_state_destructor(struct cldap_search_state *s)
554 : {
555 1082 : if (s->caller.cldap) {
556 1082 : if (s->message_id != -1) {
557 1082 : idr_remove(s->caller.cldap->searches.idr, s->message_id);
558 1082 : s->message_id = -1;
559 : }
560 1082 : DLIST_REMOVE(s->caller.cldap->searches.list, s);
561 1082 : cldap_recvfrom_stop(s->caller.cldap);
562 1082 : ZERO_STRUCT(s->caller);
563 : }
564 :
565 1082 : return 0;
566 : }
567 :
568 : static void cldap_search_state_queue_done(struct tevent_req *subreq);
569 : static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
570 :
571 : /*
572 : queue a cldap reply for send
573 : */
574 1082 : struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
575 : struct tevent_context *ev,
576 : struct cldap_socket *cldap,
577 : const struct cldap_search *io)
578 : {
579 : struct tevent_req *req, *subreq;
580 1082 : struct cldap_search_state *state = NULL;
581 : struct ldap_message *msg;
582 : struct ldap_SearchRequest *search;
583 : struct timeval now;
584 : struct timeval end;
585 : uint32_t i;
586 : int ret;
587 :
588 1082 : req = tevent_req_create(mem_ctx, &state,
589 : struct cldap_search_state);
590 1082 : if (!req) {
591 0 : return NULL;
592 : }
593 1082 : state->caller.ev = ev;
594 1082 : state->req = req;
595 1082 : state->caller.cldap = cldap;
596 1082 : state->message_id = -1;
597 :
598 1082 : talloc_set_destructor(state, cldap_search_state_destructor);
599 :
600 1082 : if (state->caller.cldap == NULL) {
601 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
602 0 : goto post;
603 : }
604 :
605 1082 : if (io->in.dest_address) {
606 0 : if (cldap->connected) {
607 0 : tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
608 0 : goto post;
609 : }
610 0 : ret = tsocket_address_inet_from_strings(state,
611 : "ip",
612 : io->in.dest_address,
613 : io->in.dest_port,
614 : &state->request.dest);
615 0 : if (ret != 0) {
616 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
617 0 : goto post;
618 : }
619 : } else {
620 1082 : if (!cldap->connected) {
621 0 : tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
622 0 : goto post;
623 : }
624 1082 : state->request.dest = NULL;
625 : }
626 :
627 1082 : state->message_id = idr_get_new_random(
628 : cldap->searches.idr, state, 1, UINT16_MAX);
629 1082 : if (state->message_id == -1) {
630 0 : tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
631 0 : goto post;
632 : }
633 :
634 1082 : msg = talloc(state, struct ldap_message);
635 1082 : if (tevent_req_nomem(msg, req)) {
636 0 : goto post;
637 : }
638 :
639 1082 : msg->messageid = state->message_id;
640 1082 : msg->type = LDAP_TAG_SearchRequest;
641 1082 : msg->controls = NULL;
642 1082 : search = &msg->r.SearchRequest;
643 :
644 1082 : search->basedn = "";
645 1082 : search->scope = LDAP_SEARCH_SCOPE_BASE;
646 1082 : search->deref = LDAP_DEREFERENCE_NEVER;
647 1082 : search->timelimit = 0;
648 1082 : search->sizelimit = 0;
649 1082 : search->attributesonly = false;
650 1082 : search->num_attributes = str_list_length(io->in.attributes);
651 1082 : search->attributes = io->in.attributes;
652 1082 : search->tree = ldb_parse_tree(msg, io->in.filter);
653 1082 : if (tevent_req_nomem(search->tree, req)) {
654 0 : goto post;
655 : }
656 :
657 1082 : if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
658 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
659 0 : goto post;
660 : }
661 1082 : talloc_free(msg);
662 :
663 1082 : state->request.idx = 0;
664 1082 : state->request.delay = 10*1000*1000;
665 1082 : state->request.count = 3;
666 1082 : if (io->in.timeout > 0) {
667 1082 : state->request.delay = io->in.timeout * 1000 * 1000;
668 1082 : state->request.count = io->in.retries + 1;
669 : }
670 :
671 1082 : now = tevent_timeval_current();
672 1082 : end = now;
673 4334 : for (i = 0; i < state->request.count; i++) {
674 3252 : end = tevent_timeval_add(&end, state->request.delay / 1000000,
675 3252 : state->request.delay % 1000000);
676 : }
677 :
678 1082 : if (!tevent_req_set_endtime(req, state->caller.ev, end)) {
679 0 : goto post;
680 : }
681 :
682 1082 : subreq = tdgram_sendto_queue_send(state,
683 1082 : state->caller.ev,
684 1082 : state->caller.cldap->sock,
685 1082 : state->caller.cldap->send_queue,
686 1082 : state->request.blob.data,
687 1082 : state->request.blob.length,
688 1082 : state->request.dest);
689 1082 : if (tevent_req_nomem(subreq, req)) {
690 0 : goto post;
691 : }
692 1082 : tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
693 :
694 1082 : DLIST_ADD_END(cldap->searches.list, state);
695 :
696 1082 : return req;
697 :
698 0 : post:
699 0 : return tevent_req_post(req, state->caller.ev);
700 : }
701 :
702 1082 : static void cldap_search_state_queue_done(struct tevent_req *subreq)
703 : {
704 1082 : struct tevent_req *req = tevent_req_callback_data(subreq,
705 : struct tevent_req);
706 1082 : struct cldap_search_state *state = tevent_req_data(req,
707 : struct cldap_search_state);
708 : ssize_t ret;
709 1082 : int sys_errno = 0;
710 : struct timeval next;
711 :
712 1082 : ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
713 1082 : talloc_free(subreq);
714 1082 : if (ret == -1) {
715 : NTSTATUS status;
716 0 : status = map_nt_error_from_unix_common(sys_errno);
717 0 : DLIST_REMOVE(state->caller.cldap->searches.list, state);
718 0 : ZERO_STRUCT(state->caller.cldap);
719 0 : tevent_req_nterror(req, status);
720 0 : return;
721 : }
722 :
723 1082 : state->request.idx++;
724 :
725 : /* wait for incoming traffic */
726 1082 : if (!cldap_recvfrom_setup(state->caller.cldap)) {
727 0 : tevent_req_oom(req);
728 0 : return;
729 : }
730 :
731 1082 : if (state->request.idx > state->request.count) {
732 : /* we just wait for the response or a timeout */
733 0 : return;
734 : }
735 :
736 1082 : next = tevent_timeval_current_ofs(state->request.delay / 1000000,
737 1082 : state->request.delay % 1000000);
738 1082 : subreq = tevent_wakeup_send(state,
739 : state->caller.ev,
740 : next);
741 1082 : if (tevent_req_nomem(subreq, req)) {
742 0 : return;
743 : }
744 1082 : tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
745 : }
746 :
747 0 : static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
748 : {
749 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
750 : struct tevent_req);
751 0 : struct cldap_search_state *state = tevent_req_data(req,
752 : struct cldap_search_state);
753 : bool ok;
754 :
755 0 : ok = tevent_wakeup_recv(subreq);
756 0 : talloc_free(subreq);
757 0 : if (!ok) {
758 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
759 0 : return;
760 : }
761 :
762 0 : subreq = tdgram_sendto_queue_send(state,
763 : state->caller.ev,
764 0 : state->caller.cldap->sock,
765 0 : state->caller.cldap->send_queue,
766 0 : state->request.blob.data,
767 : state->request.blob.length,
768 : state->request.dest);
769 0 : if (tevent_req_nomem(subreq, req)) {
770 0 : return;
771 : }
772 0 : tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
773 : }
774 :
775 : /*
776 : receive a cldap reply
777 : */
778 1082 : NTSTATUS cldap_search_recv(struct tevent_req *req,
779 : TALLOC_CTX *mem_ctx,
780 : struct cldap_search *io)
781 : {
782 1082 : struct cldap_search_state *state = tevent_req_data(req,
783 : struct cldap_search_state);
784 : struct ldap_message *ldap_msg;
785 : NTSTATUS status;
786 1082 : struct ldap_request_limits limits = {
787 : .max_search_size = MAX_SEARCH_REQUEST
788 : };
789 :
790 1082 : if (tevent_req_is_nterror(req, &status)) {
791 0 : goto failed;
792 : }
793 :
794 1082 : ldap_msg = talloc(mem_ctx, struct ldap_message);
795 1082 : if (!ldap_msg) {
796 0 : goto nomem;
797 : }
798 :
799 1082 : status = ldap_decode(state->response.asn1, &limits, NULL, ldap_msg);
800 1082 : if (!NT_STATUS_IS_OK(status)) {
801 0 : goto failed;
802 : }
803 :
804 1082 : ZERO_STRUCT(io->out);
805 :
806 : /* the first possible form has a search result in first place */
807 1082 : if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
808 1076 : io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
809 1076 : if (!io->out.response) {
810 0 : goto nomem;
811 : }
812 1076 : *io->out.response = ldap_msg->r.SearchResultEntry;
813 :
814 : /* decode the 2nd part */
815 1076 : status = ldap_decode(
816 : state->response.asn1, &limits, NULL, ldap_msg);
817 1076 : if (!NT_STATUS_IS_OK(status)) {
818 0 : goto failed;
819 : }
820 : }
821 :
822 1082 : if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
823 0 : status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
824 0 : goto failed;
825 : }
826 :
827 1082 : io->out.result = talloc(mem_ctx, struct ldap_Result);
828 1082 : if (!io->out.result) {
829 0 : goto nomem;
830 : }
831 1082 : *io->out.result = ldap_msg->r.SearchResultDone;
832 :
833 1082 : if (io->out.result->resultcode != LDAP_SUCCESS) {
834 0 : status = NT_STATUS_LDAP(io->out.result->resultcode);
835 0 : goto failed;
836 : }
837 :
838 1082 : tevent_req_received(req);
839 1082 : return NT_STATUS_OK;
840 :
841 0 : nomem:
842 0 : status = NT_STATUS_NO_MEMORY;
843 0 : failed:
844 0 : tevent_req_received(req);
845 0 : return status;
846 : }
847 :
848 :
849 : /*
850 : synchronous cldap search
851 : */
852 10 : NTSTATUS cldap_search(struct cldap_socket *cldap,
853 : TALLOC_CTX *mem_ctx,
854 : struct cldap_search *io)
855 : {
856 : TALLOC_CTX *frame;
857 : struct tevent_req *req;
858 : struct tevent_context *ev;
859 : NTSTATUS status;
860 :
861 10 : if (cldap->searches.list) {
862 0 : return NT_STATUS_PIPE_BUSY;
863 : }
864 :
865 10 : if (cldap->incoming.handler) {
866 0 : return NT_STATUS_INVALID_PIPE_STATE;
867 : }
868 :
869 10 : frame = talloc_stackframe();
870 :
871 10 : ev = samba_tevent_context_init(frame);
872 10 : if (ev == NULL) {
873 0 : TALLOC_FREE(frame);
874 0 : return NT_STATUS_NO_MEMORY;
875 : }
876 :
877 10 : req = cldap_search_send(mem_ctx, ev, cldap, io);
878 10 : if (req == NULL) {
879 0 : TALLOC_FREE(frame);
880 0 : return NT_STATUS_NO_MEMORY;
881 : }
882 :
883 10 : if (!tevent_req_poll(req, ev)) {
884 0 : status = map_nt_error_from_unix_common(errno);
885 0 : TALLOC_FREE(frame);
886 0 : return status;
887 : }
888 :
889 10 : status = cldap_search_recv(req, mem_ctx, io);
890 10 : if (!NT_STATUS_IS_OK(status)) {
891 0 : TALLOC_FREE(frame);
892 0 : return status;
893 : }
894 :
895 10 : TALLOC_FREE(frame);
896 10 : return NT_STATUS_OK;
897 : }
898 :
899 : struct cldap_netlogon_state {
900 : struct cldap_search search;
901 : };
902 :
903 1380 : char *cldap_netlogon_create_filter(TALLOC_CTX *mem_ctx,
904 : const struct cldap_netlogon *io)
905 : {
906 : char *filter;
907 :
908 1380 : filter = talloc_asprintf(mem_ctx, "(&(NtVer=%s)",
909 1380 : ldap_encode_ndr_uint32(mem_ctx, io->in.version));
910 :
911 1380 : if (io->in.user) {
912 664 : talloc_asprintf_addbuf(&filter, "(User=%s)", io->in.user);
913 : }
914 1380 : if (io->in.host) {
915 606 : talloc_asprintf_addbuf(&filter, "(Host=%s)", io->in.host);
916 : }
917 1380 : if (io->in.realm) {
918 942 : talloc_asprintf_addbuf(&filter, "(DnsDomain=%s)", io->in.realm);
919 : }
920 1380 : if (io->in.acct_control != -1) {
921 277 : talloc_asprintf_addbuf(
922 : &filter,
923 : "(AAC=%s)",
924 277 : ldap_encode_ndr_uint32(mem_ctx, io->in.acct_control));
925 : }
926 1380 : if (io->in.domain_sid) {
927 0 : struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, io->in.domain_sid);
928 :
929 0 : talloc_asprintf_addbuf(&filter, "(domainSid=%s)",
930 : ldap_encode_ndr_dom_sid(mem_ctx, sid));
931 : }
932 1380 : if (io->in.domain_guid) {
933 : struct GUID guid;
934 20 : GUID_from_string(io->in.domain_guid, &guid);
935 :
936 20 : talloc_asprintf_addbuf(&filter, "(DomainGuid=%s)",
937 : ldap_encode_ndr_GUID(mem_ctx, &guid));
938 : }
939 1380 : talloc_asprintf_addbuf(&filter, ")");
940 :
941 1380 : return filter;
942 : }
943 :
944 : static void cldap_netlogon_state_done(struct tevent_req *subreq);
945 : /*
946 : queue a cldap netlogon for send
947 : */
948 1072 : struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
949 : struct tevent_context *ev,
950 : struct cldap_socket *cldap,
951 : const struct cldap_netlogon *io)
952 : {
953 : struct tevent_req *req, *subreq;
954 : struct cldap_netlogon_state *state;
955 : char *filter;
956 : static const char * const attr[] = { "NetLogon", NULL };
957 :
958 1072 : req = tevent_req_create(mem_ctx, &state,
959 : struct cldap_netlogon_state);
960 1072 : if (!req) {
961 0 : return NULL;
962 : }
963 :
964 1072 : filter = cldap_netlogon_create_filter(state, io);
965 1072 : if (tevent_req_nomem(filter, req)) {
966 0 : goto post;
967 : }
968 :
969 1072 : if (io->in.dest_address) {
970 0 : state->search.in.dest_address = talloc_strdup(state,
971 0 : io->in.dest_address);
972 0 : if (tevent_req_nomem(state->search.in.dest_address, req)) {
973 0 : goto post;
974 : }
975 0 : state->search.in.dest_port = io->in.dest_port;
976 : } else {
977 1072 : state->search.in.dest_address = NULL;
978 1072 : state->search.in.dest_port = 0;
979 : }
980 1072 : state->search.in.filter = filter;
981 1072 : state->search.in.attributes = attr;
982 1072 : state->search.in.timeout = 2;
983 1072 : state->search.in.retries = 2;
984 :
985 1072 : subreq = cldap_search_send(state, ev, cldap, &state->search);
986 1072 : if (tevent_req_nomem(subreq, req)) {
987 0 : goto post;
988 : }
989 1072 : tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
990 :
991 1072 : return req;
992 0 : post:
993 0 : return tevent_req_post(req, ev);
994 : }
995 :
996 1072 : static void cldap_netlogon_state_done(struct tevent_req *subreq)
997 : {
998 1072 : struct tevent_req *req = tevent_req_callback_data(subreq,
999 : struct tevent_req);
1000 1072 : struct cldap_netlogon_state *state = tevent_req_data(req,
1001 : struct cldap_netlogon_state);
1002 : NTSTATUS status;
1003 :
1004 1072 : status = cldap_search_recv(subreq, state, &state->search);
1005 1072 : talloc_free(subreq);
1006 :
1007 1072 : if (tevent_req_nterror(req, status)) {
1008 0 : return;
1009 : }
1010 :
1011 1072 : tevent_req_done(req);
1012 : }
1013 :
1014 : /*
1015 : receive a cldap netlogon reply
1016 : */
1017 1072 : NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
1018 : TALLOC_CTX *mem_ctx,
1019 : struct cldap_netlogon *io)
1020 : {
1021 1072 : struct cldap_netlogon_state *state = tevent_req_data(req,
1022 : struct cldap_netlogon_state);
1023 1072 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1024 : DATA_BLOB *data;
1025 :
1026 1072 : if (tevent_req_is_nterror(req, &status)) {
1027 0 : goto failed;
1028 : }
1029 :
1030 1072 : if (state->search.out.response == NULL) {
1031 3 : status = NT_STATUS_NOT_FOUND;
1032 3 : goto failed;
1033 : }
1034 :
1035 1069 : if (state->search.out.response->num_attributes != 1 ||
1036 1069 : strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
1037 1069 : state->search.out.response->attributes[0].num_values != 1 ||
1038 1069 : state->search.out.response->attributes[0].values->length < 2) {
1039 0 : status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1040 0 : goto failed;
1041 : }
1042 1069 : data = state->search.out.response->attributes[0].values;
1043 :
1044 1069 : status = pull_netlogon_samlogon_response(data, mem_ctx,
1045 : &io->out.netlogon);
1046 1069 : if (!NT_STATUS_IS_OK(status)) {
1047 0 : goto failed;
1048 : }
1049 :
1050 1069 : if (io->in.map_response) {
1051 800 : map_netlogon_samlogon_response(&io->out.netlogon);
1052 : }
1053 :
1054 1069 : status = NT_STATUS_OK;
1055 1072 : failed:
1056 1072 : tevent_req_received(req);
1057 1072 : return status;
1058 : }
1059 :
1060 : /*
1061 : sync cldap netlogon search
1062 : */
1063 505 : NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
1064 : TALLOC_CTX *mem_ctx,
1065 : struct cldap_netlogon *io)
1066 : {
1067 : TALLOC_CTX *frame;
1068 : struct tevent_req *req;
1069 : struct tevent_context *ev;
1070 : NTSTATUS status;
1071 :
1072 505 : if (cldap->searches.list) {
1073 0 : return NT_STATUS_PIPE_BUSY;
1074 : }
1075 :
1076 505 : if (cldap->incoming.handler) {
1077 0 : return NT_STATUS_INVALID_PIPE_STATE;
1078 : }
1079 :
1080 505 : frame = talloc_stackframe();
1081 :
1082 505 : ev = samba_tevent_context_init(frame);
1083 505 : if (ev == NULL) {
1084 0 : TALLOC_FREE(frame);
1085 0 : return NT_STATUS_NO_MEMORY;
1086 : }
1087 :
1088 505 : req = cldap_netlogon_send(mem_ctx, ev, cldap, io);
1089 505 : if (req == NULL) {
1090 0 : TALLOC_FREE(frame);
1091 0 : return NT_STATUS_NO_MEMORY;
1092 : }
1093 :
1094 505 : if (!tevent_req_poll(req, ev)) {
1095 0 : status = map_nt_error_from_unix_common(errno);
1096 0 : TALLOC_FREE(frame);
1097 0 : return status;
1098 : }
1099 :
1100 505 : status = cldap_netlogon_recv(req, mem_ctx, io);
1101 505 : if (!NT_STATUS_IS_OK(status)) {
1102 3 : TALLOC_FREE(frame);
1103 3 : return status;
1104 : }
1105 :
1106 502 : TALLOC_FREE(frame);
1107 502 : return NT_STATUS_OK;
1108 : }
1109 :
1110 :
1111 : /*
1112 : send an empty reply (used on any error, so the client doesn't keep waiting
1113 : or send the bad request again)
1114 : */
1115 0 : NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1116 : uint32_t message_id,
1117 : struct tsocket_address *dest)
1118 : {
1119 : NTSTATUS status;
1120 : struct cldap_reply reply;
1121 : struct ldap_Result result;
1122 :
1123 0 : reply.messageid = message_id;
1124 0 : reply.dest = dest;
1125 0 : reply.response = NULL;
1126 0 : reply.result = &result;
1127 :
1128 0 : ZERO_STRUCT(result);
1129 :
1130 0 : status = cldap_reply_send(cldap, &reply);
1131 :
1132 0 : return status;
1133 : }
1134 :
1135 : /*
1136 : send an error reply (used on any error, so the client doesn't keep waiting
1137 : or send the bad request again)
1138 : */
1139 0 : NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
1140 : uint32_t message_id,
1141 : struct tsocket_address *dest,
1142 : int resultcode,
1143 : const char *errormessage)
1144 : {
1145 : NTSTATUS status;
1146 : struct cldap_reply reply;
1147 : struct ldap_Result result;
1148 :
1149 0 : reply.messageid = message_id;
1150 0 : reply.dest = dest;
1151 0 : reply.response = NULL;
1152 0 : reply.result = &result;
1153 :
1154 0 : ZERO_STRUCT(result);
1155 0 : result.resultcode = resultcode;
1156 0 : result.errormessage = errormessage;
1157 :
1158 0 : status = cldap_reply_send(cldap, &reply);
1159 :
1160 0 : return status;
1161 : }
1162 :
1163 :
1164 : /*
1165 : send a netlogon reply
1166 : */
1167 0 : NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
1168 : uint32_t message_id,
1169 : struct tsocket_address *dest,
1170 : uint32_t version,
1171 : struct netlogon_samlogon_response *netlogon)
1172 : {
1173 : NTSTATUS status;
1174 : struct cldap_reply reply;
1175 : struct ldap_SearchResEntry response;
1176 : struct ldap_Result result;
1177 0 : TALLOC_CTX *tmp_ctx = talloc_new(cldap);
1178 : DATA_BLOB blob;
1179 :
1180 0 : status = push_netlogon_samlogon_response(&blob, tmp_ctx,
1181 : netlogon);
1182 0 : if (!NT_STATUS_IS_OK(status)) {
1183 0 : talloc_free(tmp_ctx);
1184 0 : return status;
1185 : }
1186 0 : reply.messageid = message_id;
1187 0 : reply.dest = dest;
1188 0 : reply.response = &response;
1189 0 : reply.result = &result;
1190 :
1191 0 : ZERO_STRUCT(result);
1192 :
1193 0 : response.dn = "";
1194 0 : response.num_attributes = 1;
1195 0 : response.attributes = talloc(tmp_ctx, struct ldb_message_element);
1196 0 : NT_STATUS_HAVE_NO_MEMORY(response.attributes);
1197 0 : response.attributes->name = "netlogon";
1198 0 : response.attributes->num_values = 1;
1199 0 : response.attributes->values = &blob;
1200 :
1201 0 : status = cldap_reply_send(cldap, &reply);
1202 :
1203 0 : talloc_free(tmp_ctx);
1204 :
1205 0 : return status;
1206 : }
1207 :
|