LCOV - code coverage report
Current view: top level - source3/libsmb - unexpected.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 223 323 69.0 %
Date: 2024-06-13 04:01:37 Functions: 20 21 95.2 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    handle unexpected packets
       4             :    Copyright (C) Andrew Tridgell 2000
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : 
      19             : */
      20             : 
      21             : #include "includes.h"
      22             : #include "libsmb/unexpected.h"
      23             : #include "../lib/util/tevent_ntstatus.h"
      24             : #include "lib/util_tsock.h"
      25             : #include "libsmb/nmblib.h"
      26             : #include "lib/tsocket/tsocket.h"
      27             : #include "lib/util/sys_rw.h"
      28             : 
      29         292 : static const char *nmbd_socket_dir(void)
      30             : {
      31         292 :         return lp_parm_const_string(-1, "nmbd", "socket dir",
      32             :                                     get_dyn_NMBDSOCKETDIR());
      33             : }
      34             : 
      35             : struct nb_packet_query {
      36             :         enum packet_type type;
      37             :         size_t mailslot_namelen;
      38             :         int trn_id;
      39             : };
      40             : 
      41             : struct nb_packet_client;
      42             : 
      43             : struct nb_packet_server {
      44             :         struct tevent_context *ev;
      45             :         int listen_sock;
      46             :         struct tevent_fd *listen_fde;
      47             :         int max_clients;
      48             :         int num_clients;
      49             :         struct nb_packet_client *clients;
      50             : };
      51             : 
      52             : struct nb_packet_client {
      53             :         struct nb_packet_client *prev, *next;
      54             :         struct nb_packet_server *server;
      55             : 
      56             :         enum packet_type type;
      57             :         int trn_id;
      58             :         char *mailslot_name;
      59             : 
      60             :         struct {
      61             :                 uint8_t byte;
      62             :                 struct iovec iov[1];
      63             :         } ack;
      64             : 
      65             :         struct tstream_context *sock;
      66             :         struct tevent_queue *out_queue;
      67             : };
      68             : 
      69             : static int nb_packet_server_destructor(struct nb_packet_server *s);
      70             : static void nb_packet_server_listener(struct tevent_context *ev,
      71             :                                       struct tevent_fd *fde,
      72             :                                       uint16_t flags,
      73             :                                       void *private_data);
      74             : 
      75          23 : NTSTATUS nb_packet_server_create(TALLOC_CTX *mem_ctx,
      76             :                                  struct tevent_context *ev,
      77             :                                  int max_clients,
      78             :                                  struct nb_packet_server **presult)
      79             : {
      80             :         struct nb_packet_server *result;
      81             :         NTSTATUS status;
      82             :         int rc;
      83             : 
      84          23 :         result = talloc_zero(mem_ctx, struct nb_packet_server);
      85          23 :         if (result == NULL) {
      86           0 :                 status = NT_STATUS_NO_MEMORY;
      87           0 :                 goto fail;
      88             :         }
      89          23 :         result->ev = ev;
      90          23 :         result->max_clients = max_clients;
      91             : 
      92          23 :         result->listen_sock = create_pipe_sock(
      93             :                 nmbd_socket_dir(), "unexpected", 0755);
      94          23 :         if (result->listen_sock == -1) {
      95           0 :                 status = map_nt_error_from_unix(errno);
      96           0 :                 goto fail;
      97             :         }
      98          23 :         rc = listen(result->listen_sock, 5);
      99          23 :         if (rc < 0) {
     100           0 :                 status = map_nt_error_from_unix(errno);
     101           0 :                 goto fail;
     102             :         }
     103          23 :         talloc_set_destructor(result, nb_packet_server_destructor);
     104             : 
     105          23 :         result->listen_fde = tevent_add_fd(ev, result,
     106             :                                            result->listen_sock,
     107             :                                            TEVENT_FD_READ,
     108             :                                            nb_packet_server_listener,
     109             :                                            result);
     110          23 :         if (result->listen_fde == NULL) {
     111           0 :                 status = NT_STATUS_NO_MEMORY;
     112           0 :                 goto fail;
     113             :         }
     114             : 
     115          23 :         *presult = result;
     116          23 :         return NT_STATUS_OK;
     117           0 : fail:
     118           0 :         TALLOC_FREE(result);
     119           0 :         return status;
     120             : }
     121             : 
     122           0 : static int nb_packet_server_destructor(struct nb_packet_server *s)
     123             : {
     124           0 :         TALLOC_FREE(s->listen_fde);
     125             : 
     126           0 :         if (s->listen_sock != -1) {
     127           0 :                 close(s->listen_sock);
     128           0 :                 s->listen_sock = -1;
     129             :         }
     130           0 :         return 0;
     131             : }
     132             : 
     133             : static int nb_packet_client_destructor(struct nb_packet_client *c);
     134             : static ssize_t nb_packet_client_more(uint8_t *buf, size_t buflen,
     135             :                                      void *private_data);
     136             : static void nb_packet_got_query(struct tevent_req *req);
     137             : static void nb_packet_client_ack_done(struct tevent_req *req);
     138             : static void nb_packet_client_read_done(struct tevent_req *req);
     139             : 
     140         375 : static void nb_packet_server_listener(struct tevent_context *ev,
     141             :                                       struct tevent_fd *fde,
     142             :                                       uint16_t flags,
     143             :                                       void *private_data)
     144             : {
     145         375 :         struct nb_packet_server *server = talloc_get_type_abort(
     146             :                 private_data, struct nb_packet_server);
     147             :         struct nb_packet_client *client;
     148             :         struct tevent_req *req;
     149             :         struct sockaddr_un sunaddr;
     150             :         socklen_t len;
     151             :         int sock;
     152             :         int ret;
     153             : 
     154         375 :         len = sizeof(sunaddr);
     155             : 
     156         375 :         sock = accept(server->listen_sock, (struct sockaddr *)(void *)&sunaddr,
     157             :                       &len);
     158         375 :         if (sock == -1) {
     159           0 :                 return;
     160             :         }
     161         375 :         smb_set_close_on_exec(sock);
     162         375 :         DEBUG(6,("accepted socket %d\n", sock));
     163             : 
     164         375 :         client = talloc_zero(server, struct nb_packet_client);
     165         375 :         if (client == NULL) {
     166           0 :                 DEBUG(10, ("talloc failed\n"));
     167           0 :                 close(sock);
     168           0 :                 return;
     169             :         }
     170         375 :         ret = tstream_bsd_existing_socket(client, sock, &client->sock);
     171         375 :         if (ret != 0) {
     172           0 :                 DEBUG(10, ("tstream_bsd_existing_socket failed\n"));
     173           0 :                 TALLOC_FREE(client);
     174           0 :                 close(sock);
     175           0 :                 return;
     176             :         }
     177             : 
     178         375 :         client->server = server;
     179             : 
     180         375 :         client->out_queue = tevent_queue_create(
     181             :                 client, "unexpected packet output");
     182         375 :         if (client->out_queue == NULL) {
     183           0 :                 DEBUG(10, ("tevent_queue_create failed\n"));
     184           0 :                 TALLOC_FREE(client);
     185           0 :                 return;
     186             :         }
     187             : 
     188         375 :         req = tstream_read_packet_send(client, ev, client->sock,
     189             :                                        sizeof(struct nb_packet_query),
     190             :                                        nb_packet_client_more, NULL);
     191         375 :         if (req == NULL) {
     192           0 :                 DEBUG(10, ("tstream_read_packet_send failed\n"));
     193           0 :                 TALLOC_FREE(client);
     194           0 :                 return;
     195             :         }
     196         375 :         tevent_req_set_callback(req, nb_packet_got_query, client);
     197             : 
     198         375 :         DLIST_ADD(server->clients, client);
     199         375 :         server->num_clients += 1;
     200             : 
     201         375 :         talloc_set_destructor(client, nb_packet_client_destructor);
     202             : 
     203         375 :         if (server->num_clients > server->max_clients) {
     204           0 :                 DEBUG(10, ("Too many clients, dropping oldest\n"));
     205             : 
     206             :                 /*
     207             :                  * no TALLOC_FREE here, don't mess with the list structs
     208             :                  */
     209           0 :                 talloc_free(server->clients->prev);
     210             :         }
     211             : }
     212             : 
     213         377 : static ssize_t nb_packet_client_more(uint8_t *buf, size_t buflen,
     214             :                                      void *private_data)
     215             : {
     216             :         struct nb_packet_query q;
     217         377 :         if (buflen > sizeof(struct nb_packet_query)) {
     218           2 :                 return 0;
     219             :         }
     220             :         /* Take care of alignment */
     221         375 :         memcpy(&q, buf, sizeof(q));
     222         375 :         if (q.mailslot_namelen > 1024) {
     223           0 :                 DEBUG(10, ("Got invalid mailslot namelen %d\n",
     224             :                            (int)q.mailslot_namelen));
     225           0 :                 return -1;
     226             :         }
     227         375 :         return q.mailslot_namelen;
     228             : }
     229             : 
     230         375 : static int nb_packet_client_destructor(struct nb_packet_client *c)
     231             : {
     232         375 :         tevent_queue_stop(c->out_queue);
     233         375 :         TALLOC_FREE(c->sock);
     234             : 
     235         375 :         DLIST_REMOVE(c->server->clients, c);
     236         375 :         c->server->num_clients -= 1;
     237         375 :         return 0;
     238             : }
     239             : 
     240         375 : static void nb_packet_got_query(struct tevent_req *req)
     241             : {
     242         375 :         struct nb_packet_client *client = tevent_req_callback_data(
     243             :                 req, struct nb_packet_client);
     244             :         struct nb_packet_query q;
     245             :         uint8_t *buf;
     246             :         ssize_t nread;
     247             :         int err;
     248             : 
     249         375 :         nread = tstream_read_packet_recv(req, talloc_tos(), &buf, &err);
     250         375 :         TALLOC_FREE(req);
     251         375 :         if (nread < (ssize_t)sizeof(struct nb_packet_query)) {
     252           0 :                 DEBUG(10, ("read_packet_recv returned %d (%s)\n",
     253             :                            (int)nread,
     254             :                            (nread == -1) ? strerror(err) : "wrong length"));
     255           0 :                 TALLOC_FREE(client);
     256           0 :                 return;
     257             :         }
     258             : 
     259             :         /* Take care of alignment */
     260         375 :         memcpy(&q, buf, sizeof(q));
     261             : 
     262         375 :         if ((size_t)nread !=
     263         375 :             sizeof(struct nb_packet_query) + q.mailslot_namelen) {
     264           0 :                 DEBUG(10, ("nb_packet_got_query: Invalid mailslot namelength\n"));
     265           0 :                 TALLOC_FREE(client);
     266           0 :                 return;
     267             :         }
     268             : 
     269         375 :         client->trn_id = q.trn_id;
     270         375 :         client->type = q.type;
     271         375 :         if (q.mailslot_namelen > 0) {
     272           4 :                 client->mailslot_name = talloc_strndup(
     273           2 :                         client, (char *)buf + sizeof(q),
     274             :                         q.mailslot_namelen);
     275           2 :                 if (client->mailslot_name == NULL) {
     276           0 :                         TALLOC_FREE(client);
     277           0 :                         return;
     278             :                 }
     279             :         }
     280             : 
     281         375 :         client->ack.byte = 0;
     282         375 :         client->ack.iov[0].iov_base = &client->ack.byte;
     283         375 :         client->ack.iov[0].iov_len = 1;
     284         375 :         req = tstream_writev_queue_send(client, client->server->ev,
     285             :                                         client->sock,
     286             :                                         client->out_queue,
     287         375 :                                         client->ack.iov, 1);
     288         375 :         if (req == NULL) {
     289           0 :                 DEBUG(10, ("tstream_writev_queue_send failed\n"));
     290           0 :                 TALLOC_FREE(client);
     291           0 :                 return;
     292             :         }
     293         375 :         tevent_req_set_callback(req, nb_packet_client_ack_done, client);
     294             : 
     295         375 :         req = tstream_read_packet_send(client, client->server->ev,
     296             :                                        client->sock, 1, NULL, NULL);
     297         375 :         if (req == NULL) {
     298           0 :                 DEBUG(10, ("Could not activate reader for client exit "
     299             :                            "detection\n"));
     300           0 :                 TALLOC_FREE(client);
     301           0 :                 return;
     302             :         }
     303         375 :         tevent_req_set_callback(req, nb_packet_client_read_done,
     304             :                                 client);
     305             : }
     306             : 
     307         375 : static void nb_packet_client_ack_done(struct tevent_req *req)
     308             : {
     309         375 :         struct nb_packet_client *client = tevent_req_callback_data(
     310             :                 req, struct nb_packet_client);
     311             :         ssize_t nwritten;
     312             :         int err;
     313             : 
     314         375 :         nwritten = tstream_writev_queue_recv(req, &err);
     315             : 
     316         375 :         TALLOC_FREE(req);
     317             : 
     318         375 :         if (nwritten == -1) {
     319           0 :                 DEBUG(10, ("tstream_writev_queue_recv failed: %s\n",
     320             :                            strerror(err)));
     321           0 :                 TALLOC_FREE(client);
     322           0 :                 return;
     323             :         }
     324             : }
     325             : 
     326         375 : static void nb_packet_client_read_done(struct tevent_req *req)
     327             : {
     328         375 :         struct nb_packet_client *client = tevent_req_callback_data(
     329             :                 req, struct nb_packet_client);
     330             :         ssize_t nread;
     331             :         uint8_t *buf;
     332             :         int err;
     333             : 
     334         375 :         nread = tstream_read_packet_recv(req, talloc_tos(), &buf, &err);
     335         375 :         TALLOC_FREE(req);
     336         375 :         if (nread == 1) {
     337           0 :                 DEBUG(10, ("Protocol error, received data on write-only "
     338             :                            "unexpected socket: 0x%2.2x\n", (*buf)));
     339             :         }
     340         375 :         TALLOC_FREE(client);
     341         375 : }
     342             : 
     343             : static void nb_packet_client_send(struct nb_packet_client *client,
     344             :                                   struct packet_struct *p);
     345             : 
     346         297 : void nb_packet_dispatch(struct nb_packet_server *server,
     347             :                         struct packet_struct *p)
     348             : {
     349             :         struct nb_packet_client *c;
     350             :         uint16_t trn_id;
     351             : 
     352         297 :         switch (p->packet_type) {
     353           0 :         case NMB_PACKET:
     354           0 :                 trn_id = p->packet.nmb.header.name_trn_id;
     355           0 :                 break;
     356         297 :         case DGRAM_PACKET:
     357         297 :                 trn_id = p->packet.dgram.header.dgm_id;
     358         297 :                 break;
     359           0 :         default:
     360           0 :                 DEBUG(10, ("Got invalid packet type %d\n",
     361             :                            (int)p->packet_type));
     362           0 :                 return;
     363             :         }
     364         312 :         for (c = server->clients; c != NULL; c = c->next) {
     365             : 
     366          15 :                 if (c->type != p->packet_type) {
     367          13 :                         DEBUG(10, ("client expects packet %d, got %d\n",
     368             :                                    c->type, p->packet_type));
     369          13 :                         continue;
     370             :                 }
     371             : 
     372           2 :                 if (p->packet_type == NMB_PACKET) {
     373             :                         /*
     374             :                          * See if the client specified transaction
     375             :                          * ID. Filter if it did.
     376             :                          */
     377           0 :                         if ((c->trn_id != -1) &&
     378           0 :                             (c->trn_id != trn_id)) {
     379           0 :                                 DEBUG(10, ("client expects trn %d, got %d\n",
     380             :                                            c->trn_id, trn_id));
     381           0 :                                 continue;
     382             :                         }
     383             :                 } else {
     384             :                         /*
     385             :                          * See if the client specified a mailslot
     386             :                          * name. Filter if it did.
     387             :                          */
     388           4 :                         if ((c->mailslot_name != NULL) &&
     389           2 :                             !match_mailslot_name(p, c->mailslot_name)) {
     390           0 :                                 continue;
     391             :                         }
     392             :                 }
     393           2 :                 nb_packet_client_send(c, p);
     394             :         }
     395             : }
     396             : 
     397             : struct nb_packet_client_header {
     398             :         size_t len;
     399             :         enum packet_type type;
     400             :         time_t timestamp;
     401             :         struct in_addr ip;
     402             :         int port;
     403             : };
     404             : 
     405             : struct nb_packet_client_state {
     406             :         struct nb_packet_client *client;
     407             :         struct iovec iov[2];
     408             :         struct nb_packet_client_header hdr;
     409             :         char buf[1024];
     410             : };
     411             : 
     412             : static void nb_packet_client_send_done(struct tevent_req *req);
     413             : 
     414           2 : static void nb_packet_client_send(struct nb_packet_client *client,
     415             :                                   struct packet_struct *p)
     416             : {
     417             :         struct nb_packet_client_state *state;
     418             :         struct tevent_req *req;
     419             : 
     420           2 :         if (tevent_queue_length(client->out_queue) > 10) {
     421             :                 /*
     422             :                  * Skip clients that don't listen anyway, some form of DoS
     423             :                  * protection
     424             :                  */
     425           0 :                 return;
     426             :         }
     427             : 
     428           2 :         state = talloc_zero(client, struct nb_packet_client_state);
     429           2 :         if (state == NULL) {
     430           0 :                 DEBUG(10, ("talloc failed\n"));
     431           0 :                 return;
     432             :         }
     433             : 
     434           2 :         state->client = client;
     435             : 
     436           2 :         state->hdr.ip = p->ip;
     437           2 :         state->hdr.port = p->port;
     438           2 :         state->hdr.timestamp = p->timestamp;
     439           2 :         state->hdr.type = p->packet_type;
     440           2 :         state->hdr.len = build_packet(state->buf, sizeof(state->buf), p);
     441             : 
     442           2 :         state->iov[0].iov_base = (char *)&state->hdr;
     443           2 :         state->iov[0].iov_len = sizeof(state->hdr);
     444           2 :         state->iov[1].iov_base = state->buf;
     445           2 :         state->iov[1].iov_len = state->hdr.len;
     446             : 
     447           2 :         req = tstream_writev_queue_send(state, client->server->ev,
     448             :                                         client->sock,
     449             :                                         client->out_queue,
     450           2 :                                         state->iov, 2);
     451           2 :         if (req == NULL) {
     452           0 :                 DEBUG(10, ("tstream_writev_queue_send failed\n"));
     453           0 :                 return;
     454             :         }
     455           2 :         tevent_req_set_callback(req, nb_packet_client_send_done, state);
     456             : }
     457             : 
     458           2 : static void nb_packet_client_send_done(struct tevent_req *req)
     459             : {
     460           2 :         struct nb_packet_client_state *state = tevent_req_callback_data(
     461             :                 req, struct nb_packet_client_state);
     462           2 :         struct nb_packet_client *client = state->client;
     463             :         ssize_t nwritten;
     464             :         int err;
     465             : 
     466           2 :         nwritten = tstream_writev_queue_recv(req, &err);
     467             : 
     468           2 :         TALLOC_FREE(req);
     469           2 :         TALLOC_FREE(state);
     470             : 
     471           2 :         if (nwritten == -1) {
     472           0 :                 DEBUG(10, ("tstream_writev_queue failed: %s\n", strerror(err)));
     473           0 :                 TALLOC_FREE(client);
     474           0 :                 return;
     475             :         }
     476             : }
     477             : 
     478             : struct nb_packet_reader {
     479             :         struct tstream_context *sock;
     480             : };
     481             : 
     482             : struct nb_packet_reader_state {
     483             :         struct tevent_context *ev;
     484             :         struct nb_packet_query query;
     485             :         const char *mailslot_name;
     486             :         struct iovec iov[2];
     487             :         struct nb_packet_reader *reader;
     488             : };
     489             : 
     490             : static void nb_packet_reader_connected(struct tevent_req *subreq);
     491             : static void nb_packet_reader_sent_query(struct tevent_req *subreq);
     492             : static void nb_packet_reader_got_ack(struct tevent_req *subreq);
     493             : 
     494         269 : struct tevent_req *nb_packet_reader_send(TALLOC_CTX *mem_ctx,
     495             :                                          struct tevent_context *ev,
     496             :                                          enum packet_type type,
     497             :                                          int trn_id,
     498             :                                          const char *mailslot_name)
     499             : {
     500             :         struct tevent_req *req, *subreq;
     501             :         struct nb_packet_reader_state *state;
     502             :         struct tsocket_address *laddr;
     503             :         char *rpath;
     504             :         struct tsocket_address *raddr;
     505             :         int ret;
     506             : 
     507         269 :         req = tevent_req_create(mem_ctx, &state,
     508             :                                 struct nb_packet_reader_state);
     509         269 :         if (req == NULL) {
     510           0 :                 return NULL;
     511             :         }
     512         269 :         state->ev = ev;
     513         269 :         state->query.trn_id = trn_id;
     514         269 :         state->query.type = type;
     515         269 :         state->mailslot_name = mailslot_name;
     516             : 
     517         269 :         if (mailslot_name != NULL) {
     518           1 :                 state->query.mailslot_namelen = strlen(mailslot_name);
     519             :         }
     520             : 
     521         269 :         state->reader = talloc_zero(state, struct nb_packet_reader);
     522         269 :         if (tevent_req_nomem(state->reader, req)) {
     523           0 :                 return tevent_req_post(req, ev);
     524             :         }
     525             : 
     526         269 :         ret = tsocket_address_unix_from_path(state, NULL, &laddr);
     527         269 :         if (ret != 0) {
     528           0 :                 tevent_req_nterror(req, map_nt_error_from_unix(errno));
     529           0 :                 return tevent_req_post(req, ev);
     530             :         }
     531         269 :         rpath = talloc_asprintf(state, "%s/%s", nmbd_socket_dir(),
     532             :                                "unexpected");
     533         269 :         if (tevent_req_nomem(rpath, req)) {
     534           0 :                 return tevent_req_post(req, ev);
     535             :         }
     536         269 :         ret = tsocket_address_unix_from_path(state, rpath, &raddr);
     537         269 :         if (ret != 0) {
     538           0 :                 tevent_req_nterror(req, map_nt_error_from_unix(errno));
     539           0 :                 return tevent_req_post(req, ev);
     540             :         }
     541             : 
     542         269 :         subreq = tstream_unix_connect_send(state, ev, laddr, raddr);
     543         269 :         if (tevent_req_nomem(subreq, req)) {
     544           0 :                 return tevent_req_post(req, ev);
     545             :         }
     546         269 :         tevent_req_set_callback(subreq, nb_packet_reader_connected, req);
     547         269 :         return req;
     548             : }
     549             : 
     550         269 : static void nb_packet_reader_connected(struct tevent_req *subreq)
     551             : {
     552         269 :         struct tevent_req *req = tevent_req_callback_data(
     553             :                 subreq, struct tevent_req);
     554         269 :         struct nb_packet_reader_state *state = tevent_req_data(
     555             :                 req, struct nb_packet_reader_state);
     556             :         int res, err;
     557         269 :         int num_iovecs = 1;
     558             : 
     559         269 :         res = tstream_unix_connect_recv(subreq, &err, state->reader,
     560             :                                         &state->reader->sock);
     561         269 :         TALLOC_FREE(subreq);
     562         269 :         if (res == -1) {
     563          99 :                 DEBUG(10, ("tstream_unix_connect failed: %s\n", strerror(err)));
     564          99 :                 tevent_req_nterror(req, map_nt_error_from_unix(err));
     565          99 :                 return;
     566             :         }
     567             : 
     568         170 :         state->iov[0].iov_base = (char *)&state->query;
     569         170 :         state->iov[0].iov_len = sizeof(state->query);
     570             : 
     571         170 :         if (state->mailslot_name != NULL) {
     572           1 :                 num_iovecs = 2;
     573           1 :                 state->iov[1].iov_base = discard_const_p(
     574             :                         char, state->mailslot_name);
     575           1 :                 state->iov[1].iov_len = state->query.mailslot_namelen;
     576             :         }
     577             : 
     578         280 :         subreq = tstream_writev_send(state, state->ev, state->reader->sock,
     579         170 :                                      state->iov, num_iovecs);
     580         170 :         if (tevent_req_nomem(subreq, req)) {
     581           0 :                 return;
     582             :         }
     583         170 :         tevent_req_set_callback(subreq, nb_packet_reader_sent_query, req);
     584             : }
     585             : 
     586         170 : static void nb_packet_reader_sent_query(struct tevent_req *subreq)
     587             : {
     588         170 :         struct tevent_req *req = tevent_req_callback_data(
     589             :                 subreq, struct tevent_req);
     590         170 :         struct nb_packet_reader_state *state = tevent_req_data(
     591             :                 req, struct nb_packet_reader_state);
     592             :         ssize_t written;
     593             :         int err;
     594             : 
     595         170 :         written = tstream_writev_recv(subreq, &err);
     596         170 :         TALLOC_FREE(subreq);
     597         170 :         if (written == -1) {
     598           0 :                 tevent_req_nterror(req, map_nt_error_from_unix(err));
     599           0 :                 return;
     600             :         }
     601         170 :         if ((size_t)written !=
     602         170 :             sizeof(state->query) + state->query.mailslot_namelen) {
     603           0 :                 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
     604           0 :                 return;
     605             :         }
     606         170 :         subreq = tstream_read_packet_send(state, state->ev,
     607         170 :                                           state->reader->sock,
     608             :                                           1, NULL, NULL);
     609         170 :         if (tevent_req_nomem(subreq, req)) {
     610           0 :                 return;
     611             :         }
     612         170 :         tevent_req_set_callback(subreq, nb_packet_reader_got_ack, req);
     613             : }
     614             : 
     615         170 : static void nb_packet_reader_got_ack(struct tevent_req *subreq)
     616             : {
     617         170 :         struct tevent_req *req = tevent_req_callback_data(
     618             :                 subreq, struct tevent_req);
     619         170 :         struct nb_packet_reader_state *state = tevent_req_data(
     620             :                 req, struct nb_packet_reader_state);
     621             :         ssize_t nread;
     622             :         int err;
     623             :         uint8_t *buf;
     624             : 
     625         170 :         nread = tstream_read_packet_recv(subreq, state, &buf, &err);
     626         170 :         TALLOC_FREE(subreq);
     627         170 :         if (nread == -1) {
     628           0 :                 DEBUG(10, ("read_packet_recv returned %s\n",
     629             :                            strerror(err)));
     630           0 :                 tevent_req_nterror(req, map_nt_error_from_unix(err));
     631           0 :                 return;
     632             :         }
     633         170 :         if (nread != 1) {
     634           0 :                 DBG_DEBUG("read = %zd, expected 1\n", nread);
     635           0 :                 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
     636           0 :                 return;
     637             :         }
     638         170 :         tevent_req_done(req);
     639             : }
     640             : 
     641         269 : NTSTATUS nb_packet_reader_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     642             :                                struct nb_packet_reader **preader)
     643             : {
     644         269 :         struct nb_packet_reader_state *state = tevent_req_data(
     645             :                 req, struct nb_packet_reader_state);
     646             :         NTSTATUS status;
     647             : 
     648         269 :         if (tevent_req_is_nterror(req, &status)) {
     649          99 :                 tevent_req_received(req);
     650          99 :                 return status;
     651             :         }
     652         170 :         *preader = talloc_move(mem_ctx, &state->reader);
     653         170 :         tevent_req_received(req);
     654         170 :         return NT_STATUS_OK;
     655             : }
     656             : 
     657             : struct nb_packet_read_state {
     658             :         struct nb_packet_client_header hdr;
     659             :         uint8_t *buf;
     660             :         size_t buflen;
     661             : };
     662             : 
     663             : static ssize_t nb_packet_read_more(uint8_t *buf, size_t buflen, void *p);
     664             : static void nb_packet_read_done(struct tevent_req *subreq);
     665             : 
     666         170 : struct tevent_req *nb_packet_read_send(TALLOC_CTX *mem_ctx,
     667             :                                        struct tevent_context *ev,
     668             :                                        struct nb_packet_reader *reader)
     669             : {
     670             :         struct tevent_req *req, *subreq;
     671             :         struct nb_packet_read_state *state;
     672             : 
     673         170 :         req = tevent_req_create(mem_ctx, &state, struct nb_packet_read_state);
     674         170 :         if (req == NULL) {
     675           0 :                 return NULL;
     676             :         }
     677         170 :         subreq = tstream_read_packet_send(state, ev, reader->sock,
     678             :                                           sizeof(struct nb_packet_client_header),
     679             :                                           nb_packet_read_more, state);
     680         170 :         if (tevent_req_nomem(subreq, req)) {
     681           0 :                 return tevent_req_post(req, ev);
     682             :         }
     683         170 :         tevent_req_set_callback(subreq, nb_packet_read_done, req);
     684         170 :         return req;
     685             : }
     686             : 
     687           2 : static ssize_t nb_packet_read_more(uint8_t *buf, size_t buflen, void *p)
     688             : {
     689           2 :         struct nb_packet_read_state *state = talloc_get_type_abort(
     690             :                 p, struct nb_packet_read_state);
     691             : 
     692           2 :         if (buflen > sizeof(struct nb_packet_client_header)) {
     693             :                 /*
     694             :                  * Been here, done
     695             :                  */
     696           1 :                 return 0;
     697             :         }
     698           1 :         memcpy(&state->hdr, buf, sizeof(struct nb_packet_client_header));
     699           1 :         return state->hdr.len;
     700             : }
     701             : 
     702           1 : static void nb_packet_read_done(struct tevent_req *subreq)
     703             : {
     704           1 :         struct tevent_req *req = tevent_req_callback_data(
     705             :                 subreq, struct tevent_req);
     706           1 :         struct nb_packet_read_state *state = tevent_req_data(
     707             :                 req, struct nb_packet_read_state);
     708             :         ssize_t nread;
     709             :         int err;
     710             : 
     711           1 :         nread = tstream_read_packet_recv(subreq, state, &state->buf, &err);
     712           1 :         if (nread == -1) {
     713           0 :                 tevent_req_nterror(req, map_nt_error_from_unix(err));
     714           0 :                 return;
     715             :         }
     716           1 :         state->buflen = nread;
     717           1 :         tevent_req_done(req);
     718             : }
     719             : 
     720           1 : NTSTATUS nb_packet_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     721             :                              struct packet_struct **ppacket)
     722             : {
     723           1 :         struct nb_packet_read_state *state = tevent_req_data(
     724             :                 req, struct nb_packet_read_state);
     725             :         struct nb_packet_client_header hdr;
     726             :         struct packet_struct *packet;
     727             :         NTSTATUS status;
     728             : 
     729           1 :         if (tevent_req_is_nterror(req, &status)) {
     730           0 :                 tevent_req_received(req);
     731           0 :                 return status;
     732             :         }
     733             : 
     734           1 :         memcpy(&hdr, state->buf, sizeof(hdr));
     735             : 
     736           3 :         packet = parse_packet_talloc(
     737             :                 mem_ctx,
     738           1 :                 (char *)state->buf + sizeof(struct nb_packet_client_header),
     739           1 :                 state->buflen - sizeof(struct nb_packet_client_header),
     740             :                 state->hdr.type, state->hdr.ip, state->hdr.port);
     741           1 :         if (packet == NULL) {
     742           0 :                 tevent_req_received(req);
     743           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     744             :         }
     745             : 
     746           1 :         *ppacket = packet;
     747           1 :         tevent_req_received(req);
     748           1 :         return NT_STATUS_OK;
     749             : }

Generated by: LCOV version 1.13