summaryrefslogtreecommitdiff
path: root/source4/libcli/dgram
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2005-04-05 08:35:02 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:11:26 -0500
commit769070d502a95439ea7d6e2c6616cfa08fc5d673 (patch)
treed8bac8a0d0df76c1a135913288599d9784b0578f /source4/libcli/dgram
parente1e8928840b632297e3cbbd19aeef5e075ff7798 (diff)
downloadsamba-769070d502a95439ea7d6e2c6616cfa08fc5d673.tar.gz
samba-769070d502a95439ea7d6e2c6616cfa08fc5d673.tar.bz2
samba-769070d502a95439ea7d6e2c6616cfa08fc5d673.zip
r6209: started added code to support mailslot requests over UDP/138
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)
Diffstat (limited to 'source4/libcli/dgram')
-rw-r--r--source4/libcli/dgram/dgramsocket.c99
-rw-r--r--source4/libcli/dgram/libdgram.h77
-rw-r--r--source4/libcli/dgram/mailslot.c132
3 files changed, 302 insertions, 6 deletions
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;
+}