LCOV - code coverage report
Current view: top level - libcli/cldap - cldap.c (source / functions) Hit Total Coverage
Test: coverage report for recycleplus df22b230 Lines: 328 539 60.9 %
Date: 2024-02-14 10:14:15 Functions: 19 23 82.6 %

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

Generated by: LCOV version 1.14