LCOV - code coverage report
Current view: top level - source4/libcli/dgram - dgramsocket.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 69 109 63.3 %
Date: 2024-04-13 12:30:31 Functions: 6 6 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         768 : static void dgm_socket_recv(struct nbt_dgram_socket *dgmsock)
      34             : {
      35         768 :         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         768 :         status = socket_pending(dgmsock->sock, &dsize);
      45         768 :         if (!NT_STATUS_IS_OK(status)) {
      46           0 :                 talloc_free(tmp_ctx);
      47           0 :                 return;
      48             :         }
      49             : 
      50         768 :         blob = data_blob_talloc(tmp_ctx, NULL, dsize);
      51         768 :         if ((dsize != 0) && (blob.data == NULL)) {
      52           0 :                 talloc_free(tmp_ctx);
      53           0 :                 return;
      54             :         }
      55             : 
      56         768 :         status = socket_recvfrom(dgmsock->sock, blob.data, blob.length, &nread,
      57             :                                  tmp_ctx, &src);
      58         768 :         if (!NT_STATUS_IS_OK(status)) {
      59           0 :                 talloc_free(tmp_ctx);
      60           0 :                 return;
      61             :         }
      62         768 :         blob.length = nread;
      63             : 
      64         768 :         DEBUG(5,("Received dgram packet of length %d from %s:%d\n", 
      65             :                  (int)blob.length, src->addr, src->port));
      66             : 
      67         768 :         packet = talloc(tmp_ctx, struct nbt_dgram_packet);
      68         768 :         if (packet == NULL) {
      69           0 :                 talloc_free(tmp_ctx);
      70           0 :                 return;
      71             :         }
      72             : 
      73             :         /* parse the request */
      74         768 :         ndr_err = ndr_pull_struct_blob(&blob, packet, packet,
      75             :                                       (ndr_pull_flags_fn_t)ndr_pull_nbt_dgram_packet);
      76         768 :         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         768 :         mailslot_name = dgram_mailslot_name(packet);
      86         768 :         if (mailslot_name) {
      87           0 :                 struct dgram_mailslot_handler *dgmslot;
      88         768 :                 dgmslot = dgram_mailslot_find(dgmsock, mailslot_name);
      89         768 :                 if (dgmslot) {
      90         768 :                         dgmslot->handler(dgmslot, packet, src);
      91             :                 } else {
      92           0 :                         DEBUG(2,("No mailslot handler for '%s'\n", mailslot_name));
      93             :                 }
      94             :         } else {
      95             :                 /* dispatch if there is a general handler */
      96           0 :                 if (dgmsock->incoming.handler) {
      97           0 :                         dgmsock->incoming.handler(dgmsock, packet, src);
      98             :                 }
      99             :         }
     100             : 
     101         768 :         talloc_free(tmp_ctx);
     102             : }
     103             : 
     104             : 
     105             : /*
     106             :   handle send events on a nbt dgram socket
     107             : */
     108          66 : static void dgm_socket_send(struct nbt_dgram_socket *dgmsock)
     109             : {
     110           0 :         struct nbt_dgram_request *req;
     111           0 :         NTSTATUS status;
     112             : 
     113         132 :         while ((req = dgmsock->send_queue)) {
     114           0 :                 size_t len;
     115             :                 
     116          66 :                 len = req->encoded.length;
     117          66 :                 status = socket_sendto(dgmsock->sock, &req->encoded, &len,
     118          66 :                                        req->dest);
     119          66 :                 if (NT_STATUS_IS_ERR(status)) {
     120           0 :                         DEBUG(3,("Failed to send datagram of length %u to %s:%d: %s\n",
     121             :                                  (unsigned)req->encoded.length, req->dest->addr, req->dest->port, 
     122             :                                  nt_errstr(status)));
     123           0 :                         DLIST_REMOVE(dgmsock->send_queue, req);
     124           0 :                         talloc_free(req);
     125           0 :                         continue;
     126             :                 }
     127             : 
     128          66 :                 if (!NT_STATUS_IS_OK(status)) return;
     129             : 
     130          66 :                 DLIST_REMOVE(dgmsock->send_queue, req);
     131          66 :                 talloc_free(req);
     132             :         }
     133             : 
     134          66 :         TEVENT_FD_NOT_WRITEABLE(dgmsock->fde);
     135          66 :         return;
     136             : }
     137             : 
     138             : 
     139             : /*
     140             :   handle fd events on a nbt_dgram_socket
     141             : */
     142         834 : static void dgm_socket_handler(struct tevent_context *ev, struct tevent_fd *fde,
     143             :                                uint16_t flags, void *private_data)
     144             : {
     145         834 :         struct nbt_dgram_socket *dgmsock = talloc_get_type(private_data,
     146             :                                                            struct nbt_dgram_socket);
     147         834 :         if (flags & TEVENT_FD_WRITE) {
     148          66 :                 dgm_socket_send(dgmsock);
     149             :         } 
     150         834 :         if (flags & TEVENT_FD_READ) {
     151         768 :                 dgm_socket_recv(dgmsock);
     152             :         }
     153         834 : }
     154             : 
     155             : /*
     156             :   initialise a nbt_dgram_socket. The event_ctx is optional, if provided
     157             :   then operations will use that event context
     158             : */
     159         210 : struct nbt_dgram_socket *nbt_dgram_socket_init(TALLOC_CTX *mem_ctx, 
     160             :                                               struct tevent_context *event_ctx)
     161             : {
     162           6 :         struct nbt_dgram_socket *dgmsock;
     163           6 :         NTSTATUS status;
     164             : 
     165         210 :         dgmsock = talloc(mem_ctx, struct nbt_dgram_socket);
     166         210 :         if (dgmsock == NULL) goto failed;
     167             : 
     168         210 :         dgmsock->event_ctx = event_ctx;
     169         210 :         if (dgmsock->event_ctx == NULL) goto failed;
     170             : 
     171         210 :         status = socket_create(dgmsock, "ip", SOCKET_TYPE_DGRAM,
     172             :                                &dgmsock->sock, 0);
     173         210 :         if (!NT_STATUS_IS_OK(status)) goto failed;
     174             : 
     175         210 :         socket_set_option(dgmsock->sock, "SO_BROADCAST", "1");
     176             : 
     177         210 :         dgmsock->fde = tevent_add_fd(dgmsock->event_ctx, dgmsock,
     178             :                                     socket_get_fd(dgmsock->sock), 0,
     179             :                                     dgm_socket_handler, dgmsock);
     180             : 
     181         210 :         dgmsock->send_queue = NULL;
     182         210 :         dgmsock->incoming.handler = NULL;
     183         210 :         dgmsock->mailslot_handlers = NULL;
     184             :         
     185         210 :         return dgmsock;
     186             : 
     187           0 : failed:
     188           0 :         talloc_free(dgmsock);
     189           0 :         return NULL;
     190             : }
     191             : 
     192             : 
     193             : /*
     194             :   setup a handler for generic incoming requests
     195             : */
     196         195 : NTSTATUS dgram_set_incoming_handler(struct nbt_dgram_socket *dgmsock,
     197             :                                     void (*handler)(struct nbt_dgram_socket *, 
     198             :                                                     struct nbt_dgram_packet *, 
     199             :                                                     struct socket_address *),
     200             :                                     void *private_data)
     201             : {
     202         195 :         dgmsock->incoming.handler = handler;
     203         195 :         dgmsock->incoming.private_data = private_data;
     204         195 :         TEVENT_FD_READABLE(dgmsock->fde);
     205         195 :         return NT_STATUS_OK;
     206             : }
     207             : 
     208             : 
     209             : /*
     210             :   queue a datagram for send
     211             : */
     212          66 : NTSTATUS nbt_dgram_send(struct nbt_dgram_socket *dgmsock,
     213             :                         struct nbt_dgram_packet *packet,
     214             :                         struct socket_address *dest)
     215             : {
     216           0 :         struct nbt_dgram_request *req;
     217          66 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     218           0 :         enum ndr_err_code ndr_err;
     219             : 
     220          66 :         req = talloc(dgmsock, struct nbt_dgram_request);
     221          66 :         if (req == NULL) goto failed;
     222             : 
     223          66 :         req->dest = dest;
     224          66 :         if (talloc_reference(req, dest) == NULL) goto failed;
     225             : 
     226          66 :         ndr_err = ndr_push_struct_blob(&req->encoded, req, packet,
     227             :                                       (ndr_push_flags_fn_t)ndr_push_nbt_dgram_packet);
     228          66 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     229           0 :                 status = ndr_map_error2ntstatus(ndr_err);
     230           0 :                 goto failed;
     231             :         }
     232             : 
     233          66 :         DLIST_ADD_END(dgmsock->send_queue, req);
     234             : 
     235          66 :         TEVENT_FD_WRITEABLE(dgmsock->fde);
     236             : 
     237          66 :         return NT_STATUS_OK;
     238             : 
     239           0 : failed:
     240           0 :         talloc_free(req);
     241           0 :         return status;
     242             : }

Generated by: LCOV version 1.14