summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/libcli/config.mk4
-rw-r--r--source4/libcli/dgram/dgramsocket.c99
-rw-r--r--source4/libcli/dgram/libdgram.h77
-rw-r--r--source4/libcli/dgram/mailslot.c132
-rw-r--r--source4/librpc/idl/nbt.idl86
5 files changed, 384 insertions, 14 deletions
diff --git a/source4/libcli/config.mk b/source4/libcli/config.mk
index 51fb3c7025..f90f9907ad 100644
--- a/source4/libcli/config.mk
+++ b/source4/libcli/config.mk
@@ -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]
diff --git a/source4/libcli/dgram/dgramsocket.c b/source4/libcli/dgram/dgramsocket.c
index 7f179bc3c3..33734258a3 100644
--- a/source4/libcli/dgram/dgramsocket.c
+++ b/source4/libcli/dgram/dgramsocket.c
@@ -33,15 +33,16 @@
/*
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,13 +78,61 @@ 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
*/
static void dgm_socket_handler(struct event_context *ev, struct fd_event *fde,
@@ -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;
+}
diff --git a/source4/libcli/dgram/libdgram.h b/source4/libcli/dgram/libdgram.h
index 6ead6dccf0..866877e341 100644
--- a/source4/libcli/dgram/libdgram.h
+++ b/source4/libcli/dgram/libdgram.h
@@ -22,6 +22,21 @@
#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
index 0000000000..da9b6cdd20
--- /dev/null
+++ b/source4/libcli/dgram/mailslot.c
@@ -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;
+}
diff --git a/source4/librpc/idl/nbt.idl b/source4/librpc/idl/nbt.idl
index 4d12dd02d0..cd009530d1 100644
--- a/source4/librpc/idl/nbt.idl
+++ b/source4/librpc/idl/nbt.idl
@@ -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;