source: vendor/current/libcli/cldap/cldap.c

Last change on this file was 989, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.7

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