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