From 769070d502a95439ea7d6e2c6616cfa08fc5d673 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 5 Apr 2005 08:35:02 +0000 Subject: 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) --- source4/libcli/dgram/dgramsocket.c | 99 ++++++++++++++++++++++++++-- source4/libcli/dgram/libdgram.h | 77 ++++++++++++++++++++++ source4/libcli/dgram/mailslot.c | 132 +++++++++++++++++++++++++++++++++++++ 3 files changed, 302 insertions(+), 6 deletions(-) create mode 100644 source4/libcli/dgram/mailslot.c (limited to 'source4/libcli/dgram') 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,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; +} 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; +} -- cgit