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

Generated by: LCOV version 1.13