/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- cldap_request_destructor
- cldap_socket_recv
- cldap_request_timeout
- cldap_socket_send
- cldap_socket_handler
- cldap_socket_init
- cldap_set_incoming_handler
- cldap_search_send
- cldap_reply_send
- cldap_search_recv
- cldap_search
- cldap_netlogon_send
- cldap_netlogon_recv
- cldap_netlogon
- cldap_empty_reply
- cldap_error_reply
- cldap_netlogon_reply
1 /*
2 Unix SMB/CIFS implementation.
3
4 cldap client library
5
6 Copyright (C) Andrew Tridgell 2005
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /*
23 see RFC1798 for details of CLDAP
24
25 basic properties
26 - carried over UDP on port 389
27 - request and response matched by message ID
28 - request consists of only a single searchRequest element
29 - response can be in one of two forms
30 - a single searchResponse, followed by a searchResult
31 - a single searchResult
32 */
33
34 #include "includes.h"
35 #include "lib/events/events.h"
36 #include "../lib/util/dlinklist.h"
37 #include "libcli/ldap/ldap.h"
38 #include "libcli/ldap/ldap_ndr.h"
39 #include "libcli/cldap/cldap.h"
40 #include "lib/socket/socket.h"
41 #include "libcli/security/security.h"
42 #include "librpc/gen_ndr/ndr_nbt.h"
43
44 /*
45 destroy a pending request
46 */
47 static int cldap_request_destructor(struct cldap_request *req)
/* [<][>][^][v][top][bottom][index][help] */
48 {
49 if (req->state == CLDAP_REQUEST_SEND) {
50 DLIST_REMOVE(req->cldap->send_queue, req);
51 }
52 if (!req->is_reply && req->message_id != 0) {
53 idr_remove(req->cldap->idr, req->message_id);
54 req->message_id = 0;
55 }
56 return 0;
57 }
58
59 /*
60 handle recv events on a cldap socket
61 */
62 static void cldap_socket_recv(struct cldap_socket *cldap)
/* [<][>][^][v][top][bottom][index][help] */
63 {
64 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
65 NTSTATUS status;
66 struct socket_address *src;
67 DATA_BLOB blob;
68 size_t nread, dsize;
69 struct asn1_data *asn1 = asn1_init(tmp_ctx);
70 struct ldap_message *ldap_msg;
71 struct cldap_request *req;
72
73 if (!asn1) return;
74
75 status = socket_pending(cldap->sock, &dsize);
76 if (!NT_STATUS_IS_OK(status)) {
77 talloc_free(tmp_ctx);
78 return;
79 }
80
81 blob = data_blob_talloc(tmp_ctx, NULL, dsize);
82 if (blob.data == NULL) {
83 talloc_free(tmp_ctx);
84 return;
85 }
86
87 status = socket_recvfrom(cldap->sock, blob.data, blob.length, &nread,
88 tmp_ctx, &src);
89 if (!NT_STATUS_IS_OK(status)) {
90 talloc_free(tmp_ctx);
91 return;
92 }
93 blob.length = nread;
94
95 DEBUG(2,("Received cldap packet of length %d from %s:%d\n",
96 (int)blob.length, src->addr, src->port));
97
98 if (!asn1_load(asn1, blob)) {
99 DEBUG(2,("Failed to setup for asn.1 decode\n"));
100 talloc_free(tmp_ctx);
101 return;
102 }
103
104 ldap_msg = talloc(tmp_ctx, struct ldap_message);
105 if (ldap_msg == NULL) {
106 talloc_free(tmp_ctx);
107 return;
108 }
109
110 /* this initial decode is used to find the message id */
111 status = ldap_decode(asn1, NULL, ldap_msg);
112 if (!NT_STATUS_IS_OK(status)) {
113 DEBUG(2,("Failed to decode ldap message: %s\n", nt_errstr(status)));
114 talloc_free(tmp_ctx);
115 return;
116 }
117
118 /* find the pending request */
119 req = idr_find(cldap->idr, ldap_msg->messageid);
120 if (req == NULL) {
121 if (cldap->incoming.handler) {
122 cldap->incoming.handler(cldap, ldap_msg, src);
123 } else {
124 DEBUG(2,("Mismatched cldap reply %u from %s:%d\n",
125 ldap_msg->messageid, src->addr, src->port));
126 }
127 talloc_free(tmp_ctx);
128 return;
129 }
130
131 req->asn1 = talloc_steal(req, asn1);
132 req->asn1->ofs = 0;
133
134 req->state = CLDAP_REQUEST_DONE;
135 talloc_free(req->te);
136
137 talloc_free(tmp_ctx);
138
139 if (req->async.fn) {
140 req->async.fn(req);
141 }
142 }
143
144 /*
145 handle request timeouts
146 */
147 static void cldap_request_timeout(struct tevent_context *event_ctx,
/* [<][>][^][v][top][bottom][index][help] */
148 struct tevent_timer *te, struct timeval t,
149 void *private_data)
150 {
151 struct cldap_request *req = talloc_get_type(private_data, struct cldap_request);
152
153 /* possibly try again */
154 if (req->num_retries != 0) {
155 size_t len = req->encoded.length;
156
157 req->num_retries--;
158
159 socket_sendto(req->cldap->sock, &req->encoded, &len,
160 req->dest);
161
162 req->te = event_add_timed(req->cldap->event_ctx, req,
163 timeval_current_ofs(req->timeout, 0),
164 cldap_request_timeout, req);
165 return;
166 }
167
168 req->state = CLDAP_REQUEST_ERROR;
169 req->status = NT_STATUS_IO_TIMEOUT;
170 if (req->async.fn) {
171 req->async.fn(req);
172 }
173 }
174
175 /*
176 handle send events on a cldap socket
177 */
178 static void cldap_socket_send(struct cldap_socket *cldap)
/* [<][>][^][v][top][bottom][index][help] */
179 {
180 struct cldap_request *req;
181 NTSTATUS status;
182
183 while ((req = cldap->send_queue)) {
184 size_t len;
185
186 len = req->encoded.length;
187 status = socket_sendto(cldap->sock, &req->encoded, &len,
188 req->dest);
189 if (NT_STATUS_IS_ERR(status)) {
190 DEBUG(0,("Failed to send cldap request of length %u to %s:%d\n",
191 (unsigned)req->encoded.length, req->dest->addr, req->dest->port));
192 DLIST_REMOVE(cldap->send_queue, req);
193 req->state = CLDAP_REQUEST_ERROR;
194 req->status = status;
195 if (req->async.fn) {
196 req->async.fn(req);
197 }
198 continue;
199 }
200
201 if (!NT_STATUS_IS_OK(status)) return;
202
203 DLIST_REMOVE(cldap->send_queue, req);
204
205 if (req->is_reply) {
206 talloc_free(req);
207 } else {
208 req->state = CLDAP_REQUEST_WAIT;
209
210 req->te = event_add_timed(cldap->event_ctx, req,
211 timeval_current_ofs(req->timeout, 0),
212 cldap_request_timeout, req);
213
214 EVENT_FD_READABLE(cldap->fde);
215 }
216 }
217
218 EVENT_FD_NOT_WRITEABLE(cldap->fde);
219 return;
220 }
221
222
223 /*
224 handle fd events on a cldap_socket
225 */
226 static void cldap_socket_handler(struct tevent_context *ev, struct tevent_fd *fde,
/* [<][>][^][v][top][bottom][index][help] */
227 uint16_t flags, void *private_data)
228 {
229 struct cldap_socket *cldap = talloc_get_type(private_data, struct cldap_socket);
230 if (flags & EVENT_FD_WRITE) {
231 cldap_socket_send(cldap);
232 }
233 if (flags & EVENT_FD_READ) {
234 cldap_socket_recv(cldap);
235 }
236 }
237
238 /*
239 initialise a cldap_socket. The event_ctx is optional, if provided
240 then operations will use that event context
241 */
242 struct cldap_socket *cldap_socket_init(TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
243 struct tevent_context *event_ctx,
244 struct smb_iconv_convenience *iconv_convenience)
245 {
246 struct cldap_socket *cldap;
247 NTSTATUS status;
248
249 cldap = talloc(mem_ctx, struct cldap_socket);
250 if (cldap == NULL) goto failed;
251
252 cldap->event_ctx = talloc_reference(cldap, event_ctx);
253 if (cldap->event_ctx == NULL) goto failed;
254
255 cldap->idr = idr_init(cldap);
256 if (cldap->idr == NULL) goto failed;
257
258 status = socket_create("ip", SOCKET_TYPE_DGRAM, &cldap->sock, 0);
259 if (!NT_STATUS_IS_OK(status)) goto failed;
260
261 talloc_steal(cldap, cldap->sock);
262
263 cldap->fde = event_add_fd(cldap->event_ctx, cldap,
264 socket_get_fd(cldap->sock), 0,
265 cldap_socket_handler, cldap);
266
267 cldap->send_queue = NULL;
268 cldap->incoming.handler = NULL;
269 cldap->iconv_convenience = iconv_convenience;
270
271 return cldap;
272
273 failed:
274 talloc_free(cldap);
275 return NULL;
276 }
277
278
279 /*
280 setup a handler for incoming requests
281 */
282 NTSTATUS cldap_set_incoming_handler(struct cldap_socket *cldap,
/* [<][>][^][v][top][bottom][index][help] */
283 void (*handler)(struct cldap_socket *, struct ldap_message *,
284 struct socket_address *),
285 void *private_data)
286 {
287 cldap->incoming.handler = handler;
288 cldap->incoming.private_data = private_data;
289 EVENT_FD_READABLE(cldap->fde);
290 return NT_STATUS_OK;
291 }
292
293 /*
294 queue a cldap request for send
295 */
296 struct cldap_request *cldap_search_send(struct cldap_socket *cldap,
/* [<][>][^][v][top][bottom][index][help] */
297 struct cldap_search *io)
298 {
299 struct ldap_message *msg;
300 struct cldap_request *req;
301 struct ldap_SearchRequest *search;
302
303 req = talloc_zero(cldap, struct cldap_request);
304 if (req == NULL) goto failed;
305
306 req->cldap = cldap;
307 req->state = CLDAP_REQUEST_SEND;
308 req->timeout = io->in.timeout;
309 req->num_retries = io->in.retries;
310 req->is_reply = false;
311 req->asn1 = asn1_init(req);
312 if (!req->asn1) {
313 goto failed;
314 }
315
316 req->dest = socket_address_from_strings(req, cldap->sock->backend_name,
317 io->in.dest_address,
318 io->in.dest_port);
319 if (!req->dest) goto failed;
320
321 req->message_id = idr_get_new_random(cldap->idr, req, UINT16_MAX);
322 if (req->message_id == -1) goto failed;
323
324 talloc_set_destructor(req, cldap_request_destructor);
325
326 msg = talloc(req, struct ldap_message);
327 if (msg == NULL) goto failed;
328 msg->messageid = req->message_id;
329 msg->type = LDAP_TAG_SearchRequest;
330 msg->controls = NULL;
331 search = &msg->r.SearchRequest;
332
333 search->basedn = "";
334 search->scope = LDAP_SEARCH_SCOPE_BASE;
335 search->deref = LDAP_DEREFERENCE_NEVER;
336 search->timelimit = 0;
337 search->sizelimit = 0;
338 search->attributesonly = false;
339 search->num_attributes = str_list_length(io->in.attributes);
340 search->attributes = io->in.attributes;
341 search->tree = ldb_parse_tree(req, io->in.filter);
342 if (search->tree == NULL) {
343 goto failed;
344 }
345
346 if (!ldap_encode(msg, NULL, &req->encoded, req)) {
347 DEBUG(0,("Failed to encode cldap message to %s:%d\n",
348 req->dest->addr, req->dest->port));
349 goto failed;
350 }
351
352 DLIST_ADD_END(cldap->send_queue, req, struct cldap_request *);
353
354 EVENT_FD_WRITEABLE(cldap->fde);
355
356 return req;
357
358 failed:
359 talloc_free(req);
360 return NULL;
361 }
362
363
364 /*
365 queue a cldap reply for send
366 */
367 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
/* [<][>][^][v][top][bottom][index][help] */
368 {
369 struct ldap_message *msg;
370 struct cldap_request *req;
371 DATA_BLOB blob1, blob2;
372 NTSTATUS status = NT_STATUS_NO_MEMORY;
373
374 req = talloc_zero(cldap, struct cldap_request);
375 if (req == NULL) goto failed;
376
377 req->cldap = cldap;
378 req->state = CLDAP_REQUEST_SEND;
379 req->is_reply = true;
380 req->asn1 = asn1_init(req);
381 if (!req->asn1) {
382 goto failed;
383 }
384
385 req->dest = io->dest;
386 if (talloc_reference(req, io->dest) == NULL) goto failed;
387
388 talloc_set_destructor(req, cldap_request_destructor);
389
390 msg = talloc(req, struct ldap_message);
391 if (msg == NULL) goto failed;
392 msg->messageid = io->messageid;
393 msg->controls = NULL;
394
395 if (io->response) {
396 msg->type = LDAP_TAG_SearchResultEntry;
397 msg->r.SearchResultEntry = *io->response;
398
399 if (!ldap_encode(msg, NULL, &blob1, req)) {
400 DEBUG(0,("Failed to encode cldap message to %s:%d\n",
401 req->dest->addr, req->dest->port));
402 status = NT_STATUS_INVALID_PARAMETER;
403 goto failed;
404 }
405 } else {
406 blob1 = data_blob(NULL, 0);
407 }
408
409 msg->type = LDAP_TAG_SearchResultDone;
410 msg->r.SearchResultDone = *io->result;
411
412 if (!ldap_encode(msg, NULL, &blob2, req)) {
413 DEBUG(0,("Failed to encode cldap message to %s:%d\n",
414 req->dest->addr, req->dest->port));
415 status = NT_STATUS_INVALID_PARAMETER;
416 goto failed;
417 }
418
419 req->encoded = data_blob_talloc(req, NULL, blob1.length + blob2.length);
420 if (req->encoded.data == NULL) goto failed;
421
422 memcpy(req->encoded.data, blob1.data, blob1.length);
423 memcpy(req->encoded.data+blob1.length, blob2.data, blob2.length);
424
425 DLIST_ADD_END(cldap->send_queue, req, struct cldap_request *);
426
427 EVENT_FD_WRITEABLE(cldap->fde);
428
429 return NT_STATUS_OK;
430
431 failed:
432 talloc_free(req);
433 return status;
434 }
435
436 /*
437 receive a cldap reply
438 */
439 NTSTATUS cldap_search_recv(struct cldap_request *req,
/* [<][>][^][v][top][bottom][index][help] */
440 TALLOC_CTX *mem_ctx,
441 struct cldap_search *io)
442 {
443 struct ldap_message *ldap_msg;
444 NTSTATUS status;
445
446 if (req == NULL) {
447 return NT_STATUS_NO_MEMORY;
448 }
449
450 while (req->state < CLDAP_REQUEST_DONE) {
451 if (event_loop_once(req->cldap->event_ctx) != 0) {
452 talloc_free(req);
453 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
454 }
455 }
456
457 if (req->state == CLDAP_REQUEST_ERROR) {
458 status = req->status;
459 talloc_free(req);
460 return status;
461 }
462
463 ldap_msg = talloc(mem_ctx, struct ldap_message);
464 NT_STATUS_HAVE_NO_MEMORY(ldap_msg);
465
466 status = ldap_decode(req->asn1, NULL, ldap_msg);
467 if (!NT_STATUS_IS_OK(status)) {
468 DEBUG(2,("Failed to decode cldap search reply: %s\n", nt_errstr(status)));
469 talloc_free(req);
470 return status;
471 }
472
473 ZERO_STRUCT(io->out);
474
475 /* the first possible form has a search result in first place */
476 if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
477 io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
478 NT_STATUS_HAVE_NO_MEMORY(io->out.response);
479 *io->out.response = ldap_msg->r.SearchResultEntry;
480
481 /* decode the 2nd part */
482 status = ldap_decode(req->asn1, NULL, ldap_msg);
483 if (!NT_STATUS_IS_OK(status)) {
484 DEBUG(2,("Failed to decode cldap search result entry: %s\n", nt_errstr(status)));
485 talloc_free(req);
486 return status;
487 }
488 }
489
490 if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
491 talloc_free(req);
492 return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
493 }
494
495 io->out.result = talloc(mem_ctx, struct ldap_Result);
496 NT_STATUS_HAVE_NO_MEMORY(io->out.result);
497 *io->out.result = ldap_msg->r.SearchResultDone;
498
499 talloc_free(req);
500
501 if (io->out.result->resultcode != LDAP_SUCCESS) {
502 return NT_STATUS_LDAP(io->out.result->resultcode);
503 }
504 return NT_STATUS_OK;
505 }
506
507
508 /*
509 synchronous cldap search
510 */
511 NTSTATUS cldap_search(struct cldap_socket *cldap,
/* [<][>][^][v][top][bottom][index][help] */
512 TALLOC_CTX *mem_ctx,
513 struct cldap_search *io)
514 {
515 struct cldap_request *req = cldap_search_send(cldap, io);
516 return cldap_search_recv(req, mem_ctx, io);
517 }
518
519
520
521 /*
522 queue a cldap netlogon for send
523 */
524 struct cldap_request *cldap_netlogon_send(struct cldap_socket *cldap,
/* [<][>][^][v][top][bottom][index][help] */
525 struct cldap_netlogon *io)
526 {
527 struct cldap_search search;
528 char *filter;
529 struct cldap_request *req;
530 const char *attr[] = { "NetLogon", NULL };
531 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
532
533 filter = talloc_asprintf(tmp_ctx, "(&(NtVer=%s)",
534 ldap_encode_ndr_uint32(tmp_ctx, io->in.version));
535 if (filter == NULL) goto failed;
536 if (io->in.user) {
537 filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
538 if (filter == NULL) goto failed;
539 }
540 if (io->in.host) {
541 filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
542 if (filter == NULL) goto failed;
543 }
544 if (io->in.realm) {
545 filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
546 if (filter == NULL) goto failed;
547 }
548 if (io->in.acct_control != -1) {
549 filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)",
550 ldap_encode_ndr_uint32(tmp_ctx, io->in.acct_control));
551 if (filter == NULL) goto failed;
552 }
553 if (io->in.domain_sid) {
554 struct dom_sid *sid = dom_sid_parse_talloc(tmp_ctx, io->in.domain_sid);
555 if (sid == NULL) goto failed;
556 filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
557 ldap_encode_ndr_dom_sid(tmp_ctx, sid));
558 if (filter == NULL) goto failed;
559 }
560 if (io->in.domain_guid) {
561 struct GUID guid;
562 NTSTATUS status;
563 status = GUID_from_string(io->in.domain_guid, &guid);
564 if (!NT_STATUS_IS_OK(status)) goto failed;
565 filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
566 ldap_encode_ndr_GUID(tmp_ctx, &guid));
567 if (filter == NULL) goto failed;
568 }
569 filter = talloc_asprintf_append_buffer(filter, ")");
570 if (filter == NULL) goto failed;
571
572 search.in.dest_address = io->in.dest_address;
573 search.in.dest_port = io->in.dest_port;
574 search.in.filter = filter;
575 search.in.attributes = attr;
576 search.in.timeout = 2;
577 search.in.retries = 2;
578
579 req = cldap_search_send(cldap, &search);
580
581 talloc_free(tmp_ctx);
582 return req;
583 failed:
584 talloc_free(tmp_ctx);
585 return NULL;
586 }
587
588
589 /*
590 receive a cldap netlogon reply
591 */
592 NTSTATUS cldap_netlogon_recv(struct cldap_request *req,
/* [<][>][^][v][top][bottom][index][help] */
593 TALLOC_CTX *mem_ctx,
594 struct cldap_netlogon *io)
595 {
596 NTSTATUS status;
597 struct cldap_search search;
598 struct cldap_socket *cldap;
599 DATA_BLOB *data;
600
601 cldap = req->cldap;
602
603 status = cldap_search_recv(req, mem_ctx, &search);
604 if (!NT_STATUS_IS_OK(status)) {
605 return status;
606 }
607 if (search.out.response == NULL) {
608 return NT_STATUS_NOT_FOUND;
609 }
610
611 if (search.out.response->num_attributes != 1 ||
612 strcasecmp(search.out.response->attributes[0].name, "netlogon") != 0 ||
613 search.out.response->attributes[0].num_values != 1 ||
614 search.out.response->attributes[0].values->length < 2) {
615 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
616 }
617 data = search.out.response->attributes[0].values;
618
619 status = pull_netlogon_samlogon_response(data, mem_ctx, req->cldap->iconv_convenience,
620 &io->out.netlogon);
621 if (!NT_STATUS_IS_OK(status)) {
622 return status;
623 }
624
625 if (io->in.map_response) {
626 map_netlogon_samlogon_response(&io->out.netlogon);
627 }
628 return NT_STATUS_OK;
629 }
630
631 /*
632 sync cldap netlogon search
633 */
634 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
/* [<][>][^][v][top][bottom][index][help] */
635 TALLOC_CTX *mem_ctx, struct cldap_netlogon *io)
636 {
637 struct cldap_request *req = cldap_netlogon_send(cldap, io);
638 return cldap_netlogon_recv(req, mem_ctx, io);
639 }
640
641
642 /*
643 send an empty reply (used on any error, so the client doesn't keep waiting
644 or send the bad request again)
645 */
646 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
/* [<][>][^][v][top][bottom][index][help] */
647 uint32_t message_id,
648 struct socket_address *src)
649 {
650 NTSTATUS status;
651 struct cldap_reply reply;
652 struct ldap_Result result;
653
654 reply.messageid = message_id;
655 reply.dest = src;
656 reply.response = NULL;
657 reply.result = &result;
658
659 ZERO_STRUCT(result);
660
661 status = cldap_reply_send(cldap, &reply);
662
663 return status;
664 }
665
666 /*
667 send an error reply (used on any error, so the client doesn't keep waiting
668 or send the bad request again)
669 */
670 NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
/* [<][>][^][v][top][bottom][index][help] */
671 uint32_t message_id,
672 struct socket_address *src,
673 int resultcode,
674 const char *errormessage)
675 {
676 NTSTATUS status;
677 struct cldap_reply reply;
678 struct ldap_Result result;
679
680 reply.messageid = message_id;
681 reply.dest = src;
682 reply.response = NULL;
683 reply.result = &result;
684
685 ZERO_STRUCT(result);
686 result.resultcode = resultcode;
687 result.errormessage = errormessage;
688
689 status = cldap_reply_send(cldap, &reply);
690
691 return status;
692 }
693
694
695 /*
696 send a netlogon reply
697 */
698 NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
/* [<][>][^][v][top][bottom][index][help] */
699 uint32_t message_id,
700 struct socket_address *src,
701 uint32_t version,
702 struct netlogon_samlogon_response *netlogon)
703 {
704 NTSTATUS status;
705 struct cldap_reply reply;
706 struct ldap_SearchResEntry response;
707 struct ldap_Result result;
708 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
709 DATA_BLOB blob;
710
711 status = push_netlogon_samlogon_response(&blob, tmp_ctx, cldap->iconv_convenience,
712 netlogon);
713 if (!NT_STATUS_IS_OK(status)) {
714 return status;
715 }
716 reply.messageid = message_id;
717 reply.dest = src;
718 reply.response = &response;
719 reply.result = &result;
720
721 ZERO_STRUCT(result);
722
723 response.dn = "";
724 response.num_attributes = 1;
725 response.attributes = talloc(tmp_ctx, struct ldb_message_element);
726 NT_STATUS_HAVE_NO_MEMORY(response.attributes);
727 response.attributes->name = "netlogon";
728 response.attributes->num_values = 1;
729 response.attributes->values = &blob;
730
731 status = cldap_reply_send(cldap, &reply);
732
733 talloc_free(tmp_ctx);
734
735 return status;
736 }
737
738