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 2378 : static int cldap_socket_destructor(struct cldap_socket *c)
121 : {
122 2378 : 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 2378 : talloc_free(c->recv_subreq);
129 2378 : talloc_free(c->send_queue);
130 2378 : talloc_free(c->sock);
131 2378 : return 0;
132 : }
133 :
134 : static void cldap_recvfrom_done(struct tevent_req *subreq);
135 :
136 7257 : static bool cldap_recvfrom_setup(struct cldap_socket *c)
137 : {
138 116 : struct tevent_context *ev;
139 :
140 7257 : if (c->recv_subreq) {
141 0 : return true;
142 : }
143 :
144 7257 : if (!c->searches.list && !c->incoming.handler) {
145 2222 : return true;
146 : }
147 :
148 4999 : ev = c->incoming.ev;
149 4999 : if (ev == NULL) {
150 : /* this shouldn't happen but should be protected against */
151 2258 : if (c->searches.list == NULL) {
152 0 : return false;
153 : }
154 2258 : ev = c->searches.list->caller.ev;
155 : }
156 :
157 4999 : c->recv_subreq = tdgram_recvfrom_send(c, ev, c->sock);
158 4999 : if (!c->recv_subreq) {
159 0 : return false;
160 : }
161 4999 : tevent_req_set_callback(c->recv_subreq, cldap_recvfrom_done, c);
162 :
163 4999 : return true;
164 : }
165 :
166 2258 : static void cldap_recvfrom_stop(struct cldap_socket *c)
167 : {
168 2258 : if (!c->recv_subreq) {
169 2222 : 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 4763 : static void cldap_recvfrom_done(struct tevent_req *subreq)
184 : {
185 4763 : struct cldap_socket *c = tevent_req_callback_data(subreq,
186 : struct cldap_socket);
187 4763 : struct cldap_incoming *in = NULL;
188 72 : ssize_t ret;
189 72 : bool setup_done;
190 :
191 4763 : c->recv_subreq = NULL;
192 :
193 4763 : in = talloc_zero(c, struct cldap_incoming);
194 4763 : if (!in) {
195 0 : goto nomem;
196 : }
197 :
198 4763 : ret = tdgram_recvfrom_recv(subreq,
199 : &in->recv_errno,
200 : in,
201 : &in->buf,
202 : &in->src);
203 4763 : talloc_free(subreq);
204 4763 : subreq = NULL;
205 4763 : if (ret >= 0) {
206 4763 : in->len = ret;
207 : }
208 4763 : if (ret == -1 && in->recv_errno == 0) {
209 0 : in->recv_errno = EIO;
210 : }
211 :
212 : /* this function should free or steal 'in' */
213 4763 : setup_done = cldap_socket_recv_dgram(c, in);
214 4763 : in = NULL;
215 :
216 4763 : if (!setup_done && !cldap_recvfrom_setup(c)) {
217 0 : goto nomem;
218 : }
219 :
220 4691 : 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 4763 : static bool cldap_socket_recv_dgram(struct cldap_socket *c,
231 : struct cldap_incoming *in)
232 : {
233 72 : struct asn1_data *asn1;
234 72 : void *p;
235 72 : struct cldap_search_state *search;
236 72 : NTSTATUS status;
237 4763 : struct ldap_request_limits limits = {
238 : .max_search_size = MAX_SEARCH_REQUEST
239 : };
240 :
241 4763 : if (in->recv_errno != 0) {
242 0 : goto error;
243 : }
244 :
245 4763 : asn1 = asn1_init(in, ASN1_MAX_TREE_DEPTH);
246 4763 : if (!asn1) {
247 0 : goto nomem;
248 : }
249 :
250 4763 : asn1_load_nocopy(asn1, in->buf, in->len);
251 :
252 4763 : in->ldap_msg = talloc(in, struct ldap_message);
253 4763 : if (in->ldap_msg == NULL) {
254 0 : goto nomem;
255 : }
256 :
257 : /* this initial decode is used to find the message id */
258 4763 : status = ldap_decode(asn1, &limits, NULL, in->ldap_msg);
259 4763 : if (!NT_STATUS_IS_OK(status)) {
260 2 : goto nterror;
261 : }
262 :
263 : /* find the pending request */
264 4761 : p = idr_find(c->searches.idr, in->ldap_msg->messageid);
265 4761 : if (p == NULL) {
266 2503 : if (!c->incoming.handler) {
267 0 : TALLOC_FREE(in);
268 0 : return true;
269 : }
270 :
271 : /* this function should free or steal 'in' */
272 2503 : c->incoming.handler(c, c->incoming.private_data, in);
273 2503 : return false;
274 : }
275 :
276 2258 : search = talloc_get_type_abort(p, struct cldap_search_state);
277 2258 : search->response.in = talloc_move(search, &in);
278 :
279 2258 : search->response.asn1 = asn1;
280 :
281 2258 : asn1_load_nocopy(search->response.asn1,
282 2222 : search->response.in->buf, search->response.in->len);
283 :
284 2258 : DLIST_REMOVE(c->searches.list, search);
285 :
286 2258 : if (cldap_recvfrom_setup(c)) {
287 2258 : tevent_req_done(search->req);
288 2258 : 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 2 : nterror:
306 2 : TALLOC_FREE(in);
307 : /* in connected mode the first pending search gets the error */
308 2 : if (!c->connected) {
309 : /* otherwise we just ignore the error */
310 2 : 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 2378 : 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 2378 : struct cldap_socket *c = NULL;
336 2378 : struct tsocket_address *any = NULL;
337 44 : NTSTATUS status;
338 44 : int ret;
339 2378 : const char *fam = NULL;
340 :
341 2378 : if (local_addr == NULL && remote_addr == NULL) {
342 0 : return NT_STATUS_INVALID_PARAMETER_MIX;
343 : }
344 :
345 2378 : if (remote_addr) {
346 36 : bool is_ipv4;
347 36 : bool is_ipv6;
348 :
349 2142 : is_ipv4 = tsocket_address_is_inet(remote_addr, "ipv4");
350 2142 : is_ipv6 = tsocket_address_is_inet(remote_addr, "ipv6");
351 :
352 2142 : if (is_ipv4) {
353 1499 : fam = "ipv4";
354 607 : } else if (is_ipv6) {
355 607 : fam = "ipv6";
356 : } else {
357 0 : return NT_STATUS_INVALID_ADDRESS;
358 : }
359 : }
360 :
361 2378 : c = talloc_zero(mem_ctx, struct cldap_socket);
362 2378 : if (!c) {
363 0 : goto nomem;
364 : }
365 :
366 2378 : if (!local_addr) {
367 : /*
368 : * Here we know the address family of the remote address.
369 : */
370 2142 : if (fam == NULL) {
371 0 : return NT_STATUS_INVALID_PARAMETER_MIX;
372 : }
373 :
374 2142 : ret = tsocket_address_inet_from_strings(c, fam,
375 : NULL, 0,
376 : &any);
377 2142 : if (ret != 0) {
378 0 : status = map_nt_error_from_unix_common(errno);
379 0 : goto nterror;
380 : }
381 2142 : local_addr = any;
382 : }
383 :
384 2378 : c->searches.idr = idr_init(c);
385 2378 : if (!c->searches.idr) {
386 0 : goto nomem;
387 : }
388 :
389 2378 : ret = tdgram_inet_udp_socket(local_addr, remote_addr,
390 : c, &c->sock);
391 2378 : if (ret != 0) {
392 0 : status = map_nt_error_from_unix_common(errno);
393 0 : goto nterror;
394 : }
395 2378 : talloc_free(any);
396 :
397 2378 : if (remote_addr) {
398 2142 : c->connected = true;
399 : }
400 :
401 2378 : c->send_queue = tevent_queue_create(c, "cldap_send_queue");
402 2378 : if (!c->send_queue) {
403 0 : goto nomem;
404 : }
405 :
406 2378 : talloc_set_destructor(c, cldap_socket_destructor);
407 :
408 2378 : *_cldap = c;
409 2378 : 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 236 : 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 236 : if (c->connected) {
429 0 : return NT_STATUS_PIPE_CONNECTED;
430 : }
431 :
432 236 : c->incoming.ev = ev;
433 236 : c->incoming.handler = handler;
434 236 : c->incoming.private_data = private_data;
435 :
436 236 : if (!cldap_recvfrom_setup(c)) {
437 0 : ZERO_STRUCT(c->incoming);
438 0 : return NT_STATUS_NO_MEMORY;
439 : }
440 :
441 236 : 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 2503 : NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
455 : {
456 2503 : struct cldap_reply_state *state = NULL;
457 36 : struct ldap_message *msg;
458 36 : DATA_BLOB blob1, blob2;
459 36 : NTSTATUS status;
460 36 : struct tevent_req *subreq;
461 :
462 2503 : if (cldap->connected) {
463 0 : return NT_STATUS_PIPE_CONNECTED;
464 : }
465 :
466 2503 : if (cldap->incoming.ev == NULL) {
467 0 : return NT_STATUS_INVALID_PIPE_STATE;
468 : }
469 :
470 2503 : if (!io->dest) {
471 0 : return NT_STATUS_INVALID_ADDRESS;
472 : }
473 :
474 2503 : state = talloc(cldap, struct cldap_reply_state);
475 2503 : NT_STATUS_HAVE_NO_MEMORY(state);
476 :
477 2503 : state->dest = tsocket_address_copy(io->dest, state);
478 2503 : if (!state->dest) {
479 0 : goto nomem;
480 : }
481 :
482 2503 : msg = talloc(state, struct ldap_message);
483 2503 : if (!msg) {
484 0 : goto nomem;
485 : }
486 :
487 2503 : msg->messageid = io->messageid;
488 2503 : msg->controls = NULL;
489 :
490 2503 : if (io->response) {
491 2497 : msg->type = LDAP_TAG_SearchResultEntry;
492 2497 : msg->r.SearchResultEntry = *io->response;
493 :
494 2497 : 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 2503 : msg->type = LDAP_TAG_SearchResultDone;
503 2503 : msg->r.SearchResultDone = *io->result;
504 :
505 2503 : if (!ldap_encode(msg, NULL, &blob2, state)) {
506 0 : status = NT_STATUS_INVALID_PARAMETER;
507 0 : goto failed;
508 : }
509 2503 : talloc_free(msg);
510 :
511 2503 : state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
512 2503 : if (!state->blob.data) {
513 0 : goto nomem;
514 : }
515 :
516 2503 : if (blob1.data != NULL) {
517 2497 : memcpy(state->blob.data, blob1.data, blob1.length);
518 : }
519 2503 : memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
520 2503 : data_blob_free(&blob1);
521 2503 : data_blob_free(&blob2);
522 :
523 2539 : subreq = tdgram_sendto_queue_send(state,
524 : cldap->incoming.ev,
525 : cldap->sock,
526 : cldap->send_queue,
527 2503 : state->blob.data,
528 : state->blob.length,
529 : state->dest);
530 2503 : if (!subreq) {
531 0 : goto nomem;
532 : }
533 : /* the callback will just free the state, as we don't need a result */
534 2503 : tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
535 :
536 2503 : return NT_STATUS_OK;
537 :
538 0 : nomem:
539 0 : status = NT_STATUS_NO_MEMORY;
540 0 : failed:
541 0 : talloc_free(state);
542 0 : return status;
543 : }
544 :
545 2503 : static void cldap_reply_state_destroy(struct tevent_req *subreq)
546 : {
547 2503 : struct cldap_reply_state *state = tevent_req_callback_data(subreq,
548 : struct cldap_reply_state);
549 :
550 : /* we don't want to know the result here, we just free the state */
551 2503 : talloc_free(subreq);
552 2503 : talloc_free(state);
553 2503 : }
554 :
555 2268 : static int cldap_search_state_destructor(struct cldap_search_state *s)
556 : {
557 2268 : if (s->caller.cldap) {
558 2258 : if (s->message_id != -1) {
559 2258 : idr_remove(s->caller.cldap->searches.idr, s->message_id);
560 2258 : s->message_id = -1;
561 : }
562 2258 : DLIST_REMOVE(s->caller.cldap->searches.list, s);
563 2258 : cldap_recvfrom_stop(s->caller.cldap);
564 2258 : ZERO_STRUCT(s->caller);
565 : }
566 :
567 2268 : return 0;
568 : }
569 :
570 : static void cldap_search_state_queue_done(struct tevent_req *subreq);
571 : static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
572 :
573 : /*
574 : queue a cldap reply for send
575 : */
576 2268 : struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
577 : struct tevent_context *ev,
578 : struct cldap_socket *cldap,
579 : const struct cldap_search *io)
580 : {
581 36 : struct tevent_req *req, *subreq;
582 2268 : struct cldap_search_state *state = NULL;
583 36 : struct ldap_message *msg;
584 36 : struct ldap_SearchRequest *search;
585 36 : struct timeval now;
586 36 : struct timeval end;
587 36 : uint32_t i;
588 36 : int ret;
589 :
590 2268 : req = tevent_req_create(mem_ctx, &state,
591 : struct cldap_search_state);
592 2268 : if (!req) {
593 0 : return NULL;
594 : }
595 2268 : state->caller.ev = ev;
596 2268 : state->req = req;
597 2268 : state->caller.cldap = cldap;
598 2268 : state->message_id = -1;
599 :
600 2268 : talloc_set_destructor(state, cldap_search_state_destructor);
601 :
602 2268 : if (state->caller.cldap == NULL) {
603 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
604 0 : goto post;
605 : }
606 :
607 2268 : if (io->in.dest_address) {
608 0 : if (cldap->connected) {
609 0 : tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
610 0 : goto post;
611 : }
612 0 : ret = tsocket_address_inet_from_strings(state,
613 : "ip",
614 : io->in.dest_address,
615 : io->in.dest_port,
616 : &state->request.dest);
617 0 : if (ret != 0) {
618 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
619 0 : goto post;
620 : }
621 : } else {
622 2268 : if (!cldap->connected) {
623 0 : tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
624 0 : goto post;
625 : }
626 2268 : state->request.dest = NULL;
627 : }
628 :
629 2268 : state->message_id = idr_get_new_random(
630 : cldap->searches.idr, state, 1, UINT16_MAX);
631 2268 : if (state->message_id == -1) {
632 0 : tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
633 0 : goto post;
634 : }
635 :
636 2268 : msg = talloc(state, struct ldap_message);
637 2268 : if (tevent_req_nomem(msg, req)) {
638 0 : goto post;
639 : }
640 :
641 2268 : msg->messageid = state->message_id;
642 2268 : msg->type = LDAP_TAG_SearchRequest;
643 2268 : msg->controls = NULL;
644 2268 : search = &msg->r.SearchRequest;
645 :
646 2268 : search->basedn = "";
647 2268 : search->scope = LDAP_SEARCH_SCOPE_BASE;
648 2268 : search->deref = LDAP_DEREFERENCE_NEVER;
649 2268 : search->timelimit = 0;
650 2268 : search->sizelimit = 0;
651 2268 : search->attributesonly = false;
652 2268 : search->num_attributes = str_list_length(io->in.attributes);
653 2268 : search->attributes = io->in.attributes;
654 2268 : search->tree = ldb_parse_tree(msg, io->in.filter);
655 2268 : if (tevent_req_nomem(search->tree, req)) {
656 0 : goto post;
657 : }
658 :
659 2268 : if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
660 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
661 0 : goto post;
662 : }
663 2268 : talloc_free(msg);
664 :
665 2268 : state->request.idx = 0;
666 2268 : state->request.delay = 10*1000*1000;
667 2268 : state->request.count = 3;
668 2268 : if (io->in.timeout > 0) {
669 2268 : state->request.delay = io->in.timeout * 1000 * 1000;
670 2268 : state->request.count = io->in.retries + 1;
671 : }
672 :
673 2268 : now = tevent_timeval_current();
674 2268 : end = now;
675 9078 : for (i = 0; i < state->request.count; i++) {
676 6810 : end = tevent_timeval_add(&end, state->request.delay / 1000000,
677 6810 : state->request.delay % 1000000);
678 : }
679 :
680 2268 : if (!tevent_req_set_endtime(req, state->caller.ev, end)) {
681 0 : goto post;
682 : }
683 :
684 2304 : subreq = tdgram_sendto_queue_send(state,
685 2232 : state->caller.ev,
686 2232 : state->caller.cldap->sock,
687 2268 : state->caller.cldap->send_queue,
688 2268 : state->request.blob.data,
689 2232 : state->request.blob.length,
690 2268 : state->request.dest);
691 2268 : if (tevent_req_nomem(subreq, req)) {
692 0 : goto post;
693 : }
694 2268 : tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
695 :
696 2268 : DLIST_ADD_END(cldap->searches.list, state);
697 :
698 2232 : return req;
699 :
700 0 : post:
701 0 : return tevent_req_post(req, state->caller.ev);
702 : }
703 :
704 2268 : static void cldap_search_state_queue_done(struct tevent_req *subreq)
705 : {
706 2268 : struct tevent_req *req = tevent_req_callback_data(subreq,
707 : struct tevent_req);
708 2268 : struct cldap_search_state *state = tevent_req_data(req,
709 : struct cldap_search_state);
710 36 : ssize_t ret;
711 2268 : int sys_errno = 0;
712 36 : struct timeval next;
713 :
714 2268 : ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
715 2268 : talloc_free(subreq);
716 2268 : if (ret == -1) {
717 0 : NTSTATUS status;
718 10 : status = map_nt_error_from_unix_common(sys_errno);
719 10 : DLIST_REMOVE(state->caller.cldap->searches.list, state);
720 10 : ZERO_STRUCT(state->caller.cldap);
721 10 : tevent_req_nterror(req, status);
722 10 : return;
723 : }
724 :
725 2258 : state->request.idx++;
726 :
727 : /* wait for incoming traffic */
728 2258 : if (!cldap_recvfrom_setup(state->caller.cldap)) {
729 0 : tevent_req_oom(req);
730 0 : return;
731 : }
732 :
733 2258 : if (state->request.idx > state->request.count) {
734 : /* we just wait for the response or a timeout */
735 0 : return;
736 : }
737 :
738 2258 : next = tevent_timeval_current_ofs(state->request.delay / 1000000,
739 2258 : state->request.delay % 1000000);
740 2258 : subreq = tevent_wakeup_send(state,
741 : state->caller.ev,
742 : next);
743 2258 : if (tevent_req_nomem(subreq, req)) {
744 0 : return;
745 : }
746 2258 : tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
747 : }
748 :
749 0 : static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
750 : {
751 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
752 : struct tevent_req);
753 0 : struct cldap_search_state *state = tevent_req_data(req,
754 : struct cldap_search_state);
755 0 : bool ok;
756 :
757 0 : ok = tevent_wakeup_recv(subreq);
758 0 : talloc_free(subreq);
759 0 : if (!ok) {
760 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
761 0 : return;
762 : }
763 :
764 0 : subreq = tdgram_sendto_queue_send(state,
765 : state->caller.ev,
766 0 : state->caller.cldap->sock,
767 0 : state->caller.cldap->send_queue,
768 0 : state->request.blob.data,
769 : state->request.blob.length,
770 : state->request.dest);
771 0 : if (tevent_req_nomem(subreq, req)) {
772 0 : return;
773 : }
774 0 : tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
775 : }
776 :
777 : /*
778 : receive a cldap reply
779 : */
780 2268 : NTSTATUS cldap_search_recv(struct tevent_req *req,
781 : TALLOC_CTX *mem_ctx,
782 : struct cldap_search *io)
783 : {
784 2268 : struct cldap_search_state *state = tevent_req_data(req,
785 : struct cldap_search_state);
786 36 : struct ldap_message *ldap_msg;
787 36 : NTSTATUS status;
788 2268 : struct ldap_request_limits limits = {
789 : .max_search_size = MAX_SEARCH_REQUEST
790 : };
791 :
792 2268 : if (tevent_req_is_nterror(req, &status)) {
793 10 : goto failed;
794 : }
795 :
796 2258 : ldap_msg = talloc(mem_ctx, struct ldap_message);
797 2258 : if (!ldap_msg) {
798 0 : goto nomem;
799 : }
800 :
801 2258 : status = ldap_decode(state->response.asn1, &limits, NULL, ldap_msg);
802 2258 : if (!NT_STATUS_IS_OK(status)) {
803 0 : goto failed;
804 : }
805 :
806 2258 : ZERO_STRUCT(io->out);
807 :
808 : /* the first possible form has a search result in first place */
809 2258 : if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
810 2252 : io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
811 2252 : if (!io->out.response) {
812 0 : goto nomem;
813 : }
814 2252 : *io->out.response = ldap_msg->r.SearchResultEntry;
815 :
816 : /* decode the 2nd part */
817 2252 : status = ldap_decode(
818 : state->response.asn1, &limits, NULL, ldap_msg);
819 2252 : if (!NT_STATUS_IS_OK(status)) {
820 0 : goto failed;
821 : }
822 : }
823 :
824 2258 : if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
825 0 : status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
826 0 : goto failed;
827 : }
828 :
829 2258 : io->out.result = talloc(mem_ctx, struct ldap_Result);
830 2258 : if (!io->out.result) {
831 0 : goto nomem;
832 : }
833 2258 : *io->out.result = ldap_msg->r.SearchResultDone;
834 :
835 2258 : if (io->out.result->resultcode != LDAP_SUCCESS) {
836 0 : status = NT_STATUS_LDAP(io->out.result->resultcode);
837 0 : goto failed;
838 : }
839 :
840 2258 : tevent_req_received(req);
841 2258 : return NT_STATUS_OK;
842 :
843 0 : nomem:
844 0 : status = NT_STATUS_NO_MEMORY;
845 10 : failed:
846 10 : tevent_req_received(req);
847 10 : return status;
848 : }
849 :
850 :
851 : /*
852 : synchronous cldap search
853 : */
854 10 : NTSTATUS cldap_search(struct cldap_socket *cldap,
855 : TALLOC_CTX *mem_ctx,
856 : struct cldap_search *io)
857 : {
858 0 : TALLOC_CTX *frame;
859 0 : struct tevent_req *req;
860 0 : struct tevent_context *ev;
861 0 : NTSTATUS status;
862 :
863 10 : if (cldap->searches.list) {
864 0 : return NT_STATUS_PIPE_BUSY;
865 : }
866 :
867 10 : if (cldap->incoming.handler) {
868 0 : return NT_STATUS_INVALID_PIPE_STATE;
869 : }
870 :
871 10 : frame = talloc_stackframe();
872 :
873 10 : ev = samba_tevent_context_init(frame);
874 10 : if (ev == NULL) {
875 0 : TALLOC_FREE(frame);
876 0 : return NT_STATUS_NO_MEMORY;
877 : }
878 :
879 10 : req = cldap_search_send(mem_ctx, ev, cldap, io);
880 10 : if (req == NULL) {
881 0 : TALLOC_FREE(frame);
882 0 : return NT_STATUS_NO_MEMORY;
883 : }
884 :
885 10 : if (!tevent_req_poll(req, ev)) {
886 0 : status = map_nt_error_from_unix_common(errno);
887 0 : TALLOC_FREE(frame);
888 0 : return status;
889 : }
890 :
891 10 : status = cldap_search_recv(req, mem_ctx, io);
892 10 : if (!NT_STATUS_IS_OK(status)) {
893 0 : TALLOC_FREE(frame);
894 0 : return status;
895 : }
896 :
897 10 : TALLOC_FREE(frame);
898 10 : return NT_STATUS_OK;
899 : }
900 :
901 : struct cldap_netlogon_state {
902 : struct cldap_search search;
903 : };
904 :
905 2566 : char *cldap_netlogon_create_filter(TALLOC_CTX *mem_ctx,
906 : const struct cldap_netlogon *io)
907 : {
908 36 : char *filter;
909 :
910 2566 : filter = talloc_asprintf(mem_ctx, "(&(NtVer=%s)",
911 2566 : ldap_encode_ndr_uint32(mem_ctx, io->in.version));
912 :
913 2566 : if (io->in.user) {
914 736 : talloc_asprintf_addbuf(&filter, "(User=%s)", io->in.user);
915 : }
916 2566 : if (io->in.host) {
917 606 : talloc_asprintf_addbuf(&filter, "(Host=%s)", io->in.host);
918 : }
919 2566 : if (io->in.realm) {
920 1842 : talloc_asprintf_addbuf(&filter, "(DnsDomain=%s)", io->in.realm);
921 : }
922 2566 : if (io->in.acct_control != -1) {
923 1010 : talloc_asprintf_addbuf(
924 : &filter,
925 : "(AAC=%s)",
926 1010 : ldap_encode_ndr_uint32(mem_ctx, io->in.acct_control));
927 : }
928 2566 : if (io->in.domain_sid) {
929 0 : struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, io->in.domain_sid);
930 :
931 0 : talloc_asprintf_addbuf(&filter, "(domainSid=%s)",
932 : ldap_encode_ndr_dom_sid(mem_ctx, sid));
933 : }
934 2566 : if (io->in.domain_guid) {
935 0 : struct GUID guid;
936 20 : GUID_from_string(io->in.domain_guid, &guid);
937 :
938 20 : talloc_asprintf_addbuf(&filter, "(DomainGuid=%s)",
939 : ldap_encode_ndr_GUID(mem_ctx, &guid));
940 : }
941 2566 : talloc_asprintf_addbuf(&filter, ")");
942 :
943 2566 : return filter;
944 : }
945 :
946 : static void cldap_netlogon_state_done(struct tevent_req *subreq);
947 : /*
948 : queue a cldap netlogon for send
949 : */
950 2258 : struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
951 : struct tevent_context *ev,
952 : struct cldap_socket *cldap,
953 : const struct cldap_netlogon *io)
954 : {
955 36 : struct tevent_req *req, *subreq;
956 36 : struct cldap_netlogon_state *state;
957 36 : char *filter;
958 36 : static const char * const attr[] = { "NetLogon", NULL };
959 :
960 2258 : req = tevent_req_create(mem_ctx, &state,
961 : struct cldap_netlogon_state);
962 2258 : if (!req) {
963 0 : return NULL;
964 : }
965 :
966 2258 : filter = cldap_netlogon_create_filter(state, io);
967 2258 : if (tevent_req_nomem(filter, req)) {
968 0 : goto post;
969 : }
970 :
971 2258 : if (io->in.dest_address) {
972 0 : state->search.in.dest_address = talloc_strdup(state,
973 0 : io->in.dest_address);
974 0 : if (tevent_req_nomem(state->search.in.dest_address, req)) {
975 0 : goto post;
976 : }
977 0 : state->search.in.dest_port = io->in.dest_port;
978 : } else {
979 2258 : state->search.in.dest_address = NULL;
980 2258 : state->search.in.dest_port = 0;
981 : }
982 2258 : state->search.in.filter = filter;
983 2258 : state->search.in.attributes = attr;
984 2258 : state->search.in.timeout = 2;
985 2258 : state->search.in.retries = 2;
986 :
987 2258 : subreq = cldap_search_send(state, ev, cldap, &state->search);
988 2258 : if (tevent_req_nomem(subreq, req)) {
989 0 : goto post;
990 : }
991 2258 : tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
992 :
993 2258 : return req;
994 0 : post:
995 0 : return tevent_req_post(req, ev);
996 : }
997 :
998 2258 : static void cldap_netlogon_state_done(struct tevent_req *subreq)
999 : {
1000 2258 : struct tevent_req *req = tevent_req_callback_data(subreq,
1001 : struct tevent_req);
1002 2258 : struct cldap_netlogon_state *state = tevent_req_data(req,
1003 : struct cldap_netlogon_state);
1004 36 : NTSTATUS status;
1005 :
1006 2258 : status = cldap_search_recv(subreq, state, &state->search);
1007 2258 : talloc_free(subreq);
1008 :
1009 2258 : if (tevent_req_nterror(req, status)) {
1010 10 : return;
1011 : }
1012 :
1013 2248 : tevent_req_done(req);
1014 : }
1015 :
1016 : /*
1017 : receive a cldap netlogon reply
1018 : */
1019 2258 : NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
1020 : TALLOC_CTX *mem_ctx,
1021 : struct cldap_netlogon *io)
1022 : {
1023 2258 : struct cldap_netlogon_state *state = tevent_req_data(req,
1024 : struct cldap_netlogon_state);
1025 2258 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1026 36 : DATA_BLOB *data;
1027 :
1028 2258 : if (tevent_req_is_nterror(req, &status)) {
1029 10 : goto failed;
1030 : }
1031 :
1032 2248 : if (state->search.out.response == NULL) {
1033 3 : status = NT_STATUS_NOT_FOUND;
1034 3 : goto failed;
1035 : }
1036 :
1037 2245 : if (state->search.out.response->num_attributes != 1 ||
1038 2245 : strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
1039 2245 : state->search.out.response->attributes[0].num_values != 1 ||
1040 2245 : state->search.out.response->attributes[0].values->length < 2) {
1041 0 : status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1042 0 : goto failed;
1043 : }
1044 2245 : data = state->search.out.response->attributes[0].values;
1045 :
1046 2245 : status = pull_netlogon_samlogon_response(data, mem_ctx,
1047 : &io->out.netlogon);
1048 2245 : if (!NT_STATUS_IS_OK(status)) {
1049 0 : goto failed;
1050 : }
1051 :
1052 2245 : if (io->in.map_response) {
1053 1253 : map_netlogon_samlogon_response(&io->out.netlogon);
1054 : }
1055 :
1056 2245 : status = NT_STATUS_OK;
1057 2258 : failed:
1058 2258 : tevent_req_received(req);
1059 2258 : return status;
1060 : }
1061 :
1062 : /*
1063 : sync cldap netlogon search
1064 : */
1065 691 : NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
1066 : TALLOC_CTX *mem_ctx,
1067 : struct cldap_netlogon *io)
1068 : {
1069 36 : TALLOC_CTX *frame;
1070 36 : struct tevent_req *req;
1071 36 : struct tevent_context *ev;
1072 36 : NTSTATUS status;
1073 :
1074 691 : if (cldap->searches.list) {
1075 0 : return NT_STATUS_PIPE_BUSY;
1076 : }
1077 :
1078 691 : if (cldap->incoming.handler) {
1079 0 : return NT_STATUS_INVALID_PIPE_STATE;
1080 : }
1081 :
1082 691 : frame = talloc_stackframe();
1083 :
1084 691 : ev = samba_tevent_context_init(frame);
1085 691 : if (ev == NULL) {
1086 0 : TALLOC_FREE(frame);
1087 0 : return NT_STATUS_NO_MEMORY;
1088 : }
1089 :
1090 691 : req = cldap_netlogon_send(mem_ctx, ev, cldap, io);
1091 691 : if (req == NULL) {
1092 0 : TALLOC_FREE(frame);
1093 0 : return NT_STATUS_NO_MEMORY;
1094 : }
1095 :
1096 691 : if (!tevent_req_poll(req, ev)) {
1097 0 : status = map_nt_error_from_unix_common(errno);
1098 0 : TALLOC_FREE(frame);
1099 0 : return status;
1100 : }
1101 :
1102 691 : status = cldap_netlogon_recv(req, mem_ctx, io);
1103 691 : if (!NT_STATUS_IS_OK(status)) {
1104 3 : TALLOC_FREE(frame);
1105 3 : return status;
1106 : }
1107 :
1108 688 : TALLOC_FREE(frame);
1109 688 : return NT_STATUS_OK;
1110 : }
1111 :
1112 :
1113 : /*
1114 : send an empty reply (used on any error, so the client doesn't keep waiting
1115 : or send the bad request again)
1116 : */
1117 0 : NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1118 : uint32_t message_id,
1119 : struct tsocket_address *dest)
1120 : {
1121 0 : NTSTATUS status;
1122 0 : struct cldap_reply reply;
1123 0 : struct ldap_Result result;
1124 :
1125 0 : reply.messageid = message_id;
1126 0 : reply.dest = dest;
1127 0 : reply.response = NULL;
1128 0 : reply.result = &result;
1129 :
1130 0 : ZERO_STRUCT(result);
1131 :
1132 0 : status = cldap_reply_send(cldap, &reply);
1133 :
1134 0 : return status;
1135 : }
1136 :
1137 : /*
1138 : send an error reply (used on any error, so the client doesn't keep waiting
1139 : or send the bad request again)
1140 : */
1141 0 : NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
1142 : uint32_t message_id,
1143 : struct tsocket_address *dest,
1144 : int resultcode,
1145 : const char *errormessage)
1146 : {
1147 0 : NTSTATUS status;
1148 0 : struct cldap_reply reply;
1149 0 : struct ldap_Result result;
1150 :
1151 0 : reply.messageid = message_id;
1152 0 : reply.dest = dest;
1153 0 : reply.response = NULL;
1154 0 : reply.result = &result;
1155 :
1156 0 : ZERO_STRUCT(result);
1157 0 : result.resultcode = resultcode;
1158 0 : result.errormessage = errormessage;
1159 :
1160 0 : status = cldap_reply_send(cldap, &reply);
1161 :
1162 0 : return status;
1163 : }
1164 :
1165 :
1166 : /*
1167 : send a netlogon reply
1168 : */
1169 0 : NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
1170 : uint32_t message_id,
1171 : struct tsocket_address *dest,
1172 : uint32_t version,
1173 : struct netlogon_samlogon_response *netlogon)
1174 : {
1175 0 : NTSTATUS status;
1176 0 : struct cldap_reply reply;
1177 0 : struct ldap_SearchResEntry response;
1178 0 : struct ldap_Result result;
1179 0 : TALLOC_CTX *tmp_ctx = talloc_new(cldap);
1180 0 : DATA_BLOB blob;
1181 :
1182 0 : status = push_netlogon_samlogon_response(&blob, tmp_ctx,
1183 : netlogon);
1184 0 : if (!NT_STATUS_IS_OK(status)) {
1185 0 : talloc_free(tmp_ctx);
1186 0 : return status;
1187 : }
1188 0 : reply.messageid = message_id;
1189 0 : reply.dest = dest;
1190 0 : reply.response = &response;
1191 0 : reply.result = &result;
1192 :
1193 0 : ZERO_STRUCT(result);
1194 :
1195 0 : response.dn = "";
1196 0 : response.num_attributes = 1;
1197 0 : response.attributes = talloc(tmp_ctx, struct ldb_message_element);
1198 0 : NT_STATUS_HAVE_NO_MEMORY(response.attributes);
1199 0 : response.attributes->name = "netlogon";
1200 0 : response.attributes->num_values = 1;
1201 0 : response.attributes->values = &blob;
1202 :
1203 0 : status = cldap_reply_send(cldap, &reply);
1204 :
1205 0 : talloc_free(tmp_ctx);
1206 :
1207 0 : return status;
1208 : }
1209 :
|