r6209: started added code to support mailslot requests over UDP/138
authorAndrew Tridgell <tridge@samba.org>
Tue, 5 Apr 2005 08:35:02 +0000 (08:35 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:11:26 +0000 (13:11 -0500)
datagrams. This adds the IDL to parse mailslot packets, plus mailslot
dispatch and listener registration code.

mailslots are used for UDP/138 browse and netlogon packets
(This used to be commit f20e7e5200de736b3451d748ed716be638f93502)

source4/libcli/config.mk
source4/libcli/dgram/dgramsocket.c
source4/libcli/dgram/libdgram.h
source4/libcli/dgram/mailslot.c [new file with mode: 0644]
source4/librpc/idl/nbt.idl

index 51fb3c7025b60b8ba4b5ffdf8e7ad397f9c5211b..f90f9907ad169c451200c3dfeb373e66f0163df3 100644 (file)
@@ -37,7 +37,9 @@ REQUIRED_SUBSYSTEMS = LIBNDR_RAW NDR_NBT SOCKET LIBCLI_COMPOSITE_BASE LIBEVENTS
 
 [SUBSYSTEM::LIBCLI_DGRAM]
 ADD_OBJ_FILES = \
-       libcli/dgram/dgramsocket.o
+       libcli/dgram/dgramsocket.o \
+       libcli/dgram/mailslot.o
+NOPROTO=YES
 REQUIRED_SUBSYSTEMS = LIBCLI_NBT
 
 [SUBSYSTEM::LIBCLI_WINS]
index 7f179bc3c34c2c565317e746e994bf9975632434..33734258a371b8a47175fb84c0aa31d7241243c3 100644 (file)
 /*
   handle recv events on a nbt dgram socket
 */
-static void dgm_socket_recv(struct nbt_dgram_socket *nbtsock)
+static void dgm_socket_recv(struct nbt_dgram_socket *dgmsock)
 {
-       TALLOC_CTX *tmp_ctx = talloc_new(nbtsock);
+       TALLOC_CTX *tmp_ctx = talloc_new(dgmsock);
        NTSTATUS status;
        const char *src_addr;
        int src_port;
        DATA_BLOB blob;
        size_t nread;
        struct nbt_dgram_packet *packet;
+       const char *mailslot_name;
 
        blob = data_blob_talloc(tmp_ctx, NULL, DGRAM_MAX_PACKET_SIZE);
        if (blob.data == NULL) {
@@ -49,7 +50,7 @@ static void dgm_socket_recv(struct nbt_dgram_socket *nbtsock)
                return;
        }
 
-       status = socket_recvfrom(nbtsock->sock, blob.data, blob.length, &nread, 0,
+       status = socket_recvfrom(dgmsock->sock, blob.data, blob.length, &nread, 0,
                                 &src_addr, &src_port);
        if (!NT_STATUS_IS_OK(status)) {
                talloc_free(tmp_ctx);
@@ -77,12 +78,60 @@ static void dgm_socket_recv(struct nbt_dgram_socket *nbtsock)
                return;
        }
 
-       NDR_PRINT_DEBUG(nbt_dgram_packet, packet);
+       /* if this is a mailslot message, then see if we can dispatch it to a handler */
+       mailslot_name = dgram_mailslot_name(packet);
+       if (mailslot_name) {
+               struct dgram_mailslot_handler *dgmslot;
+               dgmslot = dgram_mailslot_find(dgmsock, mailslot_name);
+               if (dgmslot) {
+                       dgmslot->handler(dgmslot, packet, src_addr, src_port);
+               } else {
+                       DEBUG(2,("No mailslot handler for '%s'\n", mailslot_name));
+               }
+       } else {
+               /* dispatch if there is a general handler */
+               if (dgmsock->incoming.handler) {
+                       dgmsock->incoming.handler(dgmsock, packet, src_addr, src_port);
+               }
+       }
 
        talloc_free(tmp_ctx);
 }
 
 
+/*
+  handle send events on a nbt dgram socket
+*/
+static void dgm_socket_send(struct nbt_dgram_socket *dgmsock)
+{
+       struct nbt_dgram_request *req;
+       NTSTATUS status;
+
+       while ((req = dgmsock->send_queue)) {
+               size_t len;
+               
+               len = req->encoded.length;
+               status = socket_sendto(dgmsock->sock, &req->encoded, &len, 0, 
+                                      req->dest_addr, req->dest_port);
+               if (NT_STATUS_IS_ERR(status)) {
+                       DEBUG(3,("Failed to send datagram of length %u to %s:%d\n",
+                                req->encoded.length, req->dest_addr, req->dest_port));
+                       DLIST_REMOVE(dgmsock->send_queue, req);
+                       talloc_free(req);
+                       continue;
+               }
+
+               if (!NT_STATUS_IS_OK(status)) return;
+
+               DLIST_REMOVE(dgmsock->send_queue, req);
+               talloc_free(req);
+       }
+
+       EVENT_FD_NOT_WRITEABLE(dgmsock->fde);
+       return;
+}
+
+
 /*
   handle fd events on a nbt_dgram_socket
 */
@@ -92,7 +141,7 @@ static void dgm_socket_handler(struct event_context *ev, struct fd_event *fde,
        struct nbt_dgram_socket *dgmsock = talloc_get_type(private, 
                                                           struct nbt_dgram_socket);
        if (flags & EVENT_FD_WRITE) {
-               /* nothing at the moment */
+               dgm_socket_send(dgmsock);
        } else if (flags & EVENT_FD_READ) {
                dgm_socket_recv(dgmsock);
        }
@@ -128,6 +177,10 @@ struct nbt_dgram_socket *nbt_dgram_socket_init(TALLOC_CTX *mem_ctx,
        dgmsock->fde = event_add_fd(dgmsock->event_ctx, dgmsock, 
                                    socket_get_fd(dgmsock->sock), 0,
                                    dgm_socket_handler, dgmsock);
+
+       dgmsock->send_queue = NULL;
+       dgmsock->incoming.handler = NULL;
+       dgmsock->mailslot_handlers = NULL;
        
        return dgmsock;
 
@@ -138,7 +191,7 @@ failed:
 
 
 /*
-  setup a handler for incoming requests
+  setup a handler for generic incoming requests
 */
 NTSTATUS dgram_set_incoming_handler(struct nbt_dgram_socket *dgmsock,
                                    void (*handler)(struct nbt_dgram_socket *, 
@@ -151,3 +204,37 @@ NTSTATUS dgram_set_incoming_handler(struct nbt_dgram_socket *dgmsock,
        EVENT_FD_READABLE(dgmsock->fde);
        return NT_STATUS_OK;
 }
+
+
+/*
+  queue a datagram for send
+*/
+NTSTATUS nbt_dgram_send(struct nbt_dgram_socket *dgmsock,
+                       struct nbt_dgram_packet *packet,
+                       const char *dest_addr,
+                       int dest_port)
+{
+       struct nbt_dgram_request *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       req = talloc(dgmsock, struct nbt_dgram_request);
+       if (req == NULL) goto failed;
+
+       req->dest_addr = talloc_strdup(req, dest_addr);
+       if (req->dest_addr == NULL) goto failed;
+       req->dest_port = dest_port;
+
+       status = ndr_push_struct_blob(&req->encoded, req, packet, 
+                                     (ndr_push_flags_fn_t)ndr_push_nbt_dgram_packet);
+       if (!NT_STATUS_IS_OK(status)) goto failed;
+
+       DLIST_ADD_END(dgmsock->send_queue, req, struct nbt_dgram_request *);
+
+       EVENT_FD_WRITEABLE(dgmsock->fde);
+
+       return NT_STATUS_OK;
+
+failed:
+       talloc_free(req);
+       return status;
+}
index 6ead6dccf0ce17b7c00900c356c9adc488b30cb9..866877e341bfc5a223ad69d58cacbfdbb2a0e9ea 100644 (file)
 
 #include "librpc/gen_ndr/ndr_nbt.h"
 
+
+/*
+  a nbt name request
+*/
+struct nbt_dgram_request {
+       struct nbt_dgram_request *next, *prev;
+
+       /* where to send the request */
+       const char *dest_addr;
+       int dest_port;
+
+       /* the encoded request */
+       DATA_BLOB encoded;
+};
+
 /*
   context structure for operations on dgram packets
 */
@@ -32,6 +47,12 @@ struct nbt_dgram_socket {
        /* the fd event */
        struct fd_event *fde;
 
+       /* a queue of outgoing requests */
+       struct nbt_dgram_request *send_queue;
+
+       /* a list of mailslot handlers */
+       struct dgram_mailslot_handler *mailslot_handlers;
+
        /* what to do with incoming request packets */
        struct {
                void (*handler)(struct nbt_dgram_socket *, struct nbt_dgram_packet *, 
@@ -39,3 +60,59 @@ struct nbt_dgram_socket {
                void *private;
        } incoming;
 };
+
+
+/*
+  the mailslot code keeps a list of mailslot handlers. A mailslot
+  handler is a function that receives incoming packets for a specific
+  mailslot name. When a caller needs to send a mailslot and wants to
+  get a reply then it needs to register itself as listening for
+  incoming packets on the reply mailslot
+*/
+
+typedef void (*dgram_mailslot_handler_t)(struct dgram_mailslot_handler *, 
+                                        struct nbt_dgram_packet *, 
+                                        const char *, int );
+
+struct dgram_mailslot_handler {
+       struct dgram_mailslot_handler *next, *prev;
+
+       struct nbt_dgram_socket *dgmsock;
+       const char *mailslot_name;
+
+       dgram_mailslot_handler_t handler;
+       void *private;
+};
+
+
+/* prototypes */
+NTSTATUS nbt_dgram_send(struct nbt_dgram_socket *dgmsock,
+                       struct nbt_dgram_packet *packet,
+                       const char *dest_addr,
+                       int dest_port);
+NTSTATUS dgram_set_incoming_handler(struct nbt_dgram_socket *dgmsock,
+                                   void (*handler)(struct nbt_dgram_socket *, 
+                                                   struct nbt_dgram_packet *, 
+                                                   const char *, int ),
+                                   void *private);
+struct nbt_dgram_socket *nbt_dgram_socket_init(TALLOC_CTX *mem_ctx, 
+                                              struct event_context *event_ctx);
+
+const char *dgram_mailslot_name(struct nbt_dgram_packet *packet);
+struct dgram_mailslot_handler *dgram_mailslot_find(struct nbt_dgram_socket *dgmsock,
+                                                  const char *mailslot_name);
+struct dgram_mailslot_handler *dgram_mailslot_listen(struct nbt_dgram_socket *dgmsock,
+                                                    const char *mailslot_name,
+                                                    dgram_mailslot_handler_t handler,
+                                                    void *private);
+struct dgram_mailslot_handler *dgram_mailslot_temp(struct nbt_dgram_socket *dgmsock,
+                                                  const char *mailslot_name,
+                                                  dgram_mailslot_handler_t handler,
+                                                  void *private);
+
+
+
+
+
+
+
diff --git a/source4/libcli/dgram/mailslot.c b/source4/libcli/dgram/mailslot.c
new file mode 100644 (file)
index 0000000..da9b6cd
--- /dev/null
@@ -0,0 +1,132 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   packet handling for mailslot requests
+
+   Copyright (C) Andrew Tridgell 2005
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "lib/events/events.h"
+#include "dlinklist.h"
+#include "libcli/nbt/libnbt.h"
+#include "libcli/dgram/libdgram.h"
+#include "lib/socket/socket.h"
+
+/*
+  destroy a mailslot handler
+*/
+static int dgram_mailslot_destructor(void *ptr)
+{
+       struct dgram_mailslot_handler *dgmslot = 
+               talloc_get_type(ptr, struct dgram_mailslot_handler);
+       
+       DLIST_REMOVE(dgmslot->dgmsock->mailslot_handlers, dgmslot);
+       return 0;
+}
+
+/*
+  start listening on a mailslot. talloc_free() the handle to stop listening
+*/
+struct dgram_mailslot_handler *dgram_mailslot_listen(struct nbt_dgram_socket *dgmsock,
+                                                    const char *mailslot_name,
+                                                    dgram_mailslot_handler_t handler,
+                                                    void *private)
+{
+       struct dgram_mailslot_handler *dgmslot;
+
+       dgmslot = talloc(dgmsock, struct dgram_mailslot_handler);
+       if (dgmslot == NULL) return NULL;
+
+       dgmslot->dgmsock = dgmsock;
+       dgmslot->mailslot_name = talloc_strdup(dgmslot, mailslot_name);
+       if (dgmslot->mailslot_name == NULL) {
+               talloc_free(dgmslot);
+               return NULL;
+       }
+       dgmslot->handler = handler;
+       dgmslot->private = private;
+
+       DLIST_ADD(dgmsock->mailslot_handlers, dgmslot);
+       talloc_set_destructor(dgmslot, dgram_mailslot_destructor);
+
+       return dgmslot;
+}
+
+/*
+  find the handler for a specific mailslot name
+*/
+struct dgram_mailslot_handler *dgram_mailslot_find(struct nbt_dgram_socket *dgmsock,
+                                                  const char *mailslot_name)
+{
+       struct dgram_mailslot_handler *h;
+       for (h=dgmsock->mailslot_handlers;h;h=h->next) {
+               if (strcasecmp(h->mailslot_name, mailslot_name) == 0) {
+                       return h;
+               }
+       }
+       return NULL;
+}
+
+/*
+  check that a datagram packet is a valid mailslot request, and return the 
+  mailslot name if it is, otherwise return NULL
+*/
+const char *dgram_mailslot_name(struct nbt_dgram_packet *packet)
+{
+       if (packet->msg_type != DGRAM_DIRECT_UNIQUE &&
+           packet->msg_type != DGRAM_DIRECT_GROUP &&
+           packet->msg_type != DGRAM_BCAST) {
+               return NULL;
+       }
+       if (packet->data.msg.dgram_body_type != DGRAM_SMB) return NULL;
+       if (packet->data.msg.body.smb.smb_command != SMB_TRANSACTION) return NULL;
+       if (packet->data.msg.body.smb.smb_command != SMB_TRANSACTION) return NULL;
+       return packet->data.msg.body.smb.body.trans.mailslot_name;
+}
+
+
+/*
+  create a temporary mailslot handler for a reply mailslot, allocating
+  a new mailslot name using the given base name and a random integer extension
+*/
+struct dgram_mailslot_handler *dgram_mailslot_temp(struct nbt_dgram_socket *dgmsock,
+                                                  const char *mailslot_name,
+                                                  dgram_mailslot_handler_t handler,
+                                                  void *private)
+{
+       char *name;
+       int i;
+       struct dgram_mailslot_handler *dgmslot;
+
+       /* try a 100 times at most */
+       for (i=0;i<100;i++) {
+               name = talloc_asprintf(dgmsock, "%s%u", 
+                                      mailslot_name,
+                                      generate_random() % UINT16_MAX);
+               if (name == NULL) return NULL;
+               if (dgram_mailslot_find(dgmsock, name)) {
+                       talloc_free(name);
+                       return NULL;
+               }
+               dgmslot = dgram_mailslot_listen(dgmsock, name, handler, private);
+               talloc_free(name);
+               return dgmslot;
+       }
+       DEBUG(2,("Unable to create temporary mailslot from %s\n", mailslot_name));
+       return NULL;
+}
index 4d12dd02d09e9741d939e01078c197d9b80a7f0c..cd009530d156c43fd940434f4ede4e46ce42c13b 100644 (file)
@@ -213,12 +213,84 @@ interface nbt
        } dgram_node_type;
 
        /* a dgram_message is the main dgram body in general use */
+
+       /* the most common datagram type is a SMB_TRANSACTION
+          operation, where a SMB packet is used in the data section
+          of a dgram_message to hold a trans request, which in turn
+          holds a small command structure. It's a very strange beast
+          indeed. To make the code cleaner we define a basic SMB
+          packet in IDL here. This is not a general purpose SMB
+          packet, and won't be used in the core SMB client/server
+          code, but it does make working with these types of dgrams
+          easier */
+
+       typedef [enum8bit] enum {
+               SMB_TRANSACTION = 0x25
+       } smb_command;
+
        typedef struct {
-               uint16         length;
-               uint16         offset;
-               nbt_name       source_name;
-               nbt_name       dest_name;
+               [range(17,17),value(17)] uint8 wct;
+               uint16                      total_param_count;
+               uint16                      total_data_count;
+               uint16                      max_param_count;
+               uint16                      max_data_count;
+               uint8                       max_setup_count;
+               uint8                       pad;
+               uint16                      trans_flags;
+               uint32                      timeout;
+               uint16                      reserved;
+               uint16                      param_count;
+               uint16                      param_offset;
+               uint16                      data_count;
+               uint16                      data_offset;
+               [range(3,3),value(3)] uint8 setup_count;
+               uint8                       pad2;
+               uint16                      opcode;
+               uint16                      priority;
+               uint16                      class;
+               [value(strlen(r->mailslot_name)+1+r->data.length)] 
+                     uint16                byte_count;
+               astring                     mailslot_name;
                [flag(NDR_REMAINING)] DATA_BLOB data;
+       } smb_trans_body;
+
+       typedef [nodiscriminant] union {
+               [case(SMB_TRANSACTION)] smb_trans_body trans;
+       } smb_body;
+
+
+       typedef [flag(NDR_NOALIGN|NDR_LITTLE_ENDIAN|NDR_PAHEX),public] struct {
+               smb_command                smb_command;
+               uint8                      err_class;
+               uint8                      pad;
+               uint16                     err_code;
+               uint8                      flags;
+               uint16                     flags2;
+               uint16                     pid_high;
+               uint8                      signature[8];
+               uint16                     reserved;
+               uint16                     tid;
+               uint16                     pid;
+               uint16                     vuid;
+               uint16                     mid;
+               [switch_is(smb_command)]   smb_body body;
+       } dgram_smb_packet;
+
+       typedef [v1_enum] enum {
+               DGRAM_SMB = 0xff534d42 /* 0xffSMB */
+       } dgram_body_type;
+
+       typedef [nodiscriminant] union {
+               [case(DGRAM_SMB)] dgram_smb_packet smb;
+       } dgram_message_body;
+
+       typedef struct {
+               uint16          length;
+               uint16          offset;
+               nbt_name        source_name;
+               nbt_name        dest_name;
+               dgram_body_type dgram_body_type;
+               [switch_is(dgram_body_type)] dgram_message_body body;
        } dgram_message;
 
        typedef [enum8bit] enum {
@@ -228,9 +300,9 @@ interface nbt
        } dgram_err_code;
 
        typedef [nodiscriminant] union {
-               [case(DGRAM_DIRECT_UNIQUE)]   dgram_message msg;
-               [case(DGRAM_DIRECT_GROUP)]    dgram_message msg;
-               [case(DGRAM_BCAST)]           dgram_message msg;
+               [case(DGRAM_DIRECT_UNIQUE)]   dgram_message  msg;
+               [case(DGRAM_DIRECT_GROUP)]    dgram_message  msg;
+               [case(DGRAM_BCAST)]           dgram_message  msg;
                [case(DGRAM_ERROR)]           dgram_err_code error;
                [case(DGRAM_QUERY)]           nbt_name       dest_name;
                [case(DGRAM_QUERY_POSITIVE)]  nbt_name       dest_name;