diff options
-rw-r--r-- | source4/libcli/config.mk | 4 | ||||
-rw-r--r-- | source4/libcli/dgram/dgramsocket.c | 99 | ||||
-rw-r--r-- | source4/libcli/dgram/libdgram.h | 77 | ||||
-rw-r--r-- | source4/libcli/dgram/mailslot.c | 132 | ||||
-rw-r--r-- | source4/librpc/idl/nbt.idl | 86 |
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; |