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

Generated by: LCOV version 1.14