source: trunk/server/libcli/cldap/cldap.c@ 823

Last change on this file since 823 was 752, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.9 2nd part

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