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

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

Samba Server: updated trunk to 3.6.0

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