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

Generated by: LCOV version 1.14