LCOV - code coverage report
Current view: top level - source4/libcli/dgram - dgramsocket.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 83 129 64.3 %
Date: 2024-05-31 13:13:24 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    low level socket handling for nbt dgram requests (UDP138)
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2005
       7             :    
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             :    
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             :    
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "lib/events/events.h"
      24             : #include "../lib/util/dlinklist.h"
      25             : #include "libcli/dgram/libdgram.h"
      26             : #include "lib/socket/socket.h"
      27             : #include "librpc/gen_ndr/ndr_nbt.h"
      28             : 
      29             : 
      30             : /*
      31             :   handle recv events on a nbt dgram socket
      32             : */
      33         960 : static void dgm_socket_recv(struct nbt_dgram_socket *dgmsock)
      34             : {
      35         960 :         TALLOC_CTX *tmp_ctx = talloc_new(dgmsock);
      36           0 :         NTSTATUS status;
      37           0 :         struct socket_address *src;
      38           0 :         DATA_BLOB blob;
      39           0 :         size_t nread, dsize;
      40           0 :         struct nbt_dgram_packet *packet;
      41           0 :         const char *mailslot_name;
      42           0 :         enum ndr_err_code ndr_err;
      43             : 
      44         960 :         status = socket_pending(dgmsock->sock, &dsize);
      45         960 :         if (!NT_STATUS_IS_OK(status)) {
      46           0 :                 talloc_free(tmp_ctx);
      47           0 :                 return;
      48             :         }
      49             : 
      50         960 :         blob = data_blob_talloc(tmp_ctx, NULL, dsize);
      51         960 :         if ((dsize != 0) && (blob.data == NULL)) {
      52           0 :                 talloc_free(tmp_ctx);
      53           0 :                 return;
      54             :         }
      55             : 
      56         960 :         status = socket_recvfrom(dgmsock->sock, blob.data, blob.length, &nread,
      57             :                                  tmp_ctx, &src);
      58         960 :         if (!NT_STATUS_IS_OK(status)) {
      59           0 :                 talloc_free(tmp_ctx);
      60           0 :                 return;
      61             :         }
      62         960 :         blob.length = nread;
      63             : 
      64         960 :         DEBUG(5,("Received dgram packet of length %d from %s:%d\n", 
      65             :                  (int)blob.length, src->addr, src->port));
      66             : 
      67         960 :         packet = talloc(tmp_ctx, struct nbt_dgram_packet);
      68         960 :         if (packet == NULL) {
      69           0 :                 talloc_free(tmp_ctx);
      70           0 :                 return;
      71             :         }
      72             : 
      73             :         /* parse the request */
      74         960 :         ndr_err = ndr_pull_struct_blob(&blob, packet, packet,
      75             :                                       (ndr_pull_flags_fn_t)ndr_pull_nbt_dgram_packet);
      76         960 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
      77           0 :                 status = ndr_map_error2ntstatus(ndr_err);
      78           0 :                 DEBUG(2,("Failed to parse incoming NBT DGRAM packet - %s\n",
      79             :                          nt_errstr(status)));
      80           0 :                 talloc_free(tmp_ctx);
      81           0 :                 return;
      82             :         }
      83             : 
      84             :         /* if this is a mailslot message, then see if we can dispatch it to a handler */
      85         960 :         mailslot_name = dgram_mailslot_name(packet);
      86         960 :         if (mailslot_name) {
      87           0 :                 struct dgram_mailslot_handler *dgmslot;
      88         960 :                 dgmslot = dgram_mailslot_find(dgmsock, mailslot_name);
      89         960 :                 if (dgmslot) {
      90         945 :                         dgmslot->handler(dgmslot, packet, src);
      91             :                 } else {
      92          15 :                         DEBUG(2,("No mailslot handler for '%s'\n", mailslot_name));
      93             :                         /* dispatch if there is a general handler */
      94          15 :                         if (dgmsock->incoming.handler) {
      95          15 :                                 dgmsock->incoming.handler(dgmsock, packet, src);
      96             :                         }
      97             :                 }
      98             :         } else {
      99             :                 /* dispatch if there is a general handler */
     100           0 :                 if (dgmsock->incoming.handler) {
     101           0 :                         dgmsock->incoming.handler(dgmsock, packet, src);
     102             :                 }
     103             :         }
     104             : 
     105         960 :         talloc_free(tmp_ctx);
     106             : }
     107             : 
     108             : 
     109             : /*
     110             :   handle send events on a nbt dgram socket
     111             : */
     112         102 : static void dgm_socket_send(struct nbt_dgram_socket *dgmsock)
     113             : {
     114           0 :         struct nbt_dgram_request *req;
     115           0 :         NTSTATUS status;
     116             : 
     117         204 :         while ((req = dgmsock->send_queue)) {
     118           0 :                 size_t len;
     119             :                 
     120         102 :                 len = req->encoded.length;
     121         102 :                 status = socket_sendto(dgmsock->sock, &req->encoded, &len,
     122         102 :                                        req->dest);
     123         102 :                 if (NT_STATUS_IS_ERR(status)) {
     124           0 :                         DEBUG(3,("Failed to send datagram of length %u to %s:%d: %s\n",
     125             :                                  (unsigned)req->encoded.length, req->dest->addr, req->dest->port, 
     126             :                                  nt_errstr(status)));
     127           0 :                         DLIST_REMOVE(dgmsock->send_queue, req);
     128           0 :                         talloc_free(req);
     129           0 :                         continue;
     130             :                 }
     131             : 
     132         102 :                 if (!NT_STATUS_IS_OK(status)) return;
     133             : 
     134         102 :                 DLIST_REMOVE(dgmsock->send_queue, req);
     135         102 :                 talloc_free(req);
     136             :         }
     137             : 
     138         102 :         TEVENT_FD_NOT_WRITEABLE(dgmsock->fde);
     139         102 :         return;
     140             : }
     141             : 
     142             : 
     143             : /*
     144             :   handle fd events on a nbt_dgram_socket
     145             : */
     146        1062 : static void dgm_socket_handler(struct tevent_context *ev, struct tevent_fd *fde,
     147             :                                uint16_t flags, void *private_data)
     148             : {
     149        1062 :         struct nbt_dgram_socket *dgmsock = talloc_get_type(private_data,
     150             :                                                            struct nbt_dgram_socket);
     151        1062 :         if (flags & TEVENT_FD_WRITE) {
     152         102 :                 dgm_socket_send(dgmsock);
     153             :         } 
     154        1062 :         if (flags & TEVENT_FD_READ) {
     155         960 :                 dgm_socket_recv(dgmsock);
     156             :         }
     157        1062 : }
     158             : 
     159             : /*
     160             :   initialise a nbt_dgram_socket. The event_ctx is optional, if provided
     161             :   then operations will use that event context
     162             : */
     163         210 : struct nbt_dgram_socket *nbt_dgram_socket_init(TALLOC_CTX *mem_ctx, 
     164             :                                               struct tevent_context *event_ctx)
     165             : {
     166           6 :         struct nbt_dgram_socket *dgmsock;
     167           6 :         NTSTATUS status;
     168             : 
     169         210 :         dgmsock = talloc(mem_ctx, struct nbt_dgram_socket);
     170         210 :         if (dgmsock == NULL) goto failed;
     171             : 
     172         210 :         dgmsock->event_ctx = event_ctx;
     173         210 :         if (dgmsock->event_ctx == NULL) goto failed;
     174             : 
     175         210 :         status = socket_create(dgmsock, "ip", SOCKET_TYPE_DGRAM,
     176             :                                &dgmsock->sock, 0);
     177         210 :         if (!NT_STATUS_IS_OK(status)) goto failed;
     178             : 
     179         210 :         socket_set_option(dgmsock->sock, "SO_BROADCAST", "1");
     180             : 
     181         210 :         dgmsock->fde = tevent_add_fd(dgmsock->event_ctx, dgmsock,
     182             :                                     socket_get_fd(dgmsock->sock), 0,
     183             :                                     dgm_socket_handler, dgmsock);
     184             : 
     185         210 :         dgmsock->send_queue = NULL;
     186         210 :         dgmsock->incoming.handler = NULL;
     187         210 :         dgmsock->mailslot_handlers = NULL;
     188             :         
     189         210 :         return dgmsock;
     190             : 
     191           0 : failed:
     192           0 :         talloc_free(dgmsock);
     193           0 :         return NULL;
     194             : }
     195             : 
     196             : 
     197             : /*
     198             :   setup a handler for generic incoming requests
     199             : */
     200         195 : NTSTATUS dgram_set_incoming_handler(struct nbt_dgram_socket *dgmsock,
     201             :                                     void (*handler)(struct nbt_dgram_socket *, 
     202             :                                                     struct nbt_dgram_packet *, 
     203             :                                                     struct socket_address *),
     204             :                                     void *private_data)
     205             : {
     206         195 :         dgmsock->incoming.handler = handler;
     207         195 :         dgmsock->incoming.private_data = private_data;
     208         195 :         TEVENT_FD_READABLE(dgmsock->fde);
     209         195 :         return NT_STATUS_OK;
     210             : }
     211             : 
     212          15 : NTSTATUS nbt_dgram_send_raw(struct nbt_dgram_socket *dgmsock,
     213             :                             struct socket_address *dest,
     214             :                             const DATA_BLOB pkt_blob)
     215             : {
     216           0 :         struct nbt_dgram_request *req;
     217          15 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     218             : 
     219          15 :         req = talloc(dgmsock, struct nbt_dgram_request);
     220          15 :         if (req == NULL) {
     221           0 :                 goto failed;
     222             :         }
     223             : 
     224          15 :         req->dest = socket_address_copy(req, dest);
     225          15 :         if (req->dest == NULL) {
     226           0 :                 goto failed;
     227             :         }
     228             : 
     229          15 :         req->encoded = data_blob_dup_talloc(req, pkt_blob);
     230          15 :         if (req->encoded.length != pkt_blob.length) {
     231           0 :                 goto failed;
     232             :         }
     233             : 
     234          15 :         DLIST_ADD_END(dgmsock->send_queue, req);
     235             : 
     236          15 :         TEVENT_FD_WRITEABLE(dgmsock->fde);
     237             : 
     238          15 :         return NT_STATUS_OK;
     239             : 
     240           0 : failed:
     241           0 :         talloc_free(req);
     242           0 :         return status;
     243             : }
     244             : 
     245             : /*
     246             :   queue a datagram for send
     247             : */
     248          87 : NTSTATUS nbt_dgram_send(struct nbt_dgram_socket *dgmsock,
     249             :                         struct nbt_dgram_packet *packet,
     250             :                         struct socket_address *dest)
     251             : {
     252           0 :         struct nbt_dgram_request *req;
     253          87 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     254           0 :         enum ndr_err_code ndr_err;
     255             : 
     256          87 :         req = talloc(dgmsock, struct nbt_dgram_request);
     257          87 :         if (req == NULL) goto failed;
     258             : 
     259          87 :         req->dest = socket_address_copy(req, dest);
     260          87 :         if (req->dest == NULL) goto failed;
     261             : 
     262          87 :         ndr_err = ndr_push_struct_blob(&req->encoded, req, packet,
     263             :                                       (ndr_push_flags_fn_t)ndr_push_nbt_dgram_packet);
     264          87 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     265           0 :                 status = ndr_map_error2ntstatus(ndr_err);
     266           0 :                 goto failed;
     267             :         }
     268             : 
     269          87 :         DLIST_ADD_END(dgmsock->send_queue, req);
     270             : 
     271          87 :         TEVENT_FD_WRITEABLE(dgmsock->fde);
     272             : 
     273          87 :         return NT_STATUS_OK;
     274             : 
     275           0 : failed:
     276           0 :         talloc_free(req);
     277           0 :         return status;
     278             : }

Generated by: LCOV version 1.14