source: branches/samba-3.5.x/libcli/cldap/cldap.c@ 734

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

Samba Server 3.5: update branche to 3.5.14

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