diff options
Diffstat (limited to 'source4')
-rw-r--r-- | source4/libcli/dgram/dgramsocket.c | 153 | ||||
-rw-r--r-- | source4/libcli/dgram/libdgram.h | 41 | ||||
-rw-r--r-- | source4/librpc/idl/nbt.idl | 62 | ||||
-rw-r--r-- | source4/nbt_server/interfaces.c | 48 | ||||
-rw-r--r-- | source4/nbt_server/nbt_server.h | 2 | ||||
-rw-r--r-- | source4/nbt_server/register.c | 12 | ||||
-rw-r--r-- | source4/param/loadparm.c | 4 |
7 files changed, 319 insertions, 3 deletions
diff --git a/source4/libcli/dgram/dgramsocket.c b/source4/libcli/dgram/dgramsocket.c new file mode 100644 index 0000000000..7f179bc3c3 --- /dev/null +++ b/source4/libcli/dgram/dgramsocket.c @@ -0,0 +1,153 @@ +/* + Unix SMB/CIFS implementation. + + low level socket handling for nbt dgram requests (UDP138) + + 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" + +#define DGRAM_MAX_PACKET_SIZE 2048 + + +/* + handle recv events on a nbt dgram socket +*/ +static void dgm_socket_recv(struct nbt_dgram_socket *nbtsock) +{ + TALLOC_CTX *tmp_ctx = talloc_new(nbtsock); + NTSTATUS status; + const char *src_addr; + int src_port; + DATA_BLOB blob; + size_t nread; + struct nbt_dgram_packet *packet; + + blob = data_blob_talloc(tmp_ctx, NULL, DGRAM_MAX_PACKET_SIZE); + if (blob.data == NULL) { + talloc_free(tmp_ctx); + return; + } + + status = socket_recvfrom(nbtsock->sock, blob.data, blob.length, &nread, 0, + &src_addr, &src_port); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return; + } + talloc_steal(tmp_ctx, src_addr); + blob.length = nread; + + DEBUG(0,("Received dgram packet of length %d from %s:%d\n", + blob.length, src_addr, src_port)); + + packet = talloc(tmp_ctx, struct nbt_dgram_packet); + if (packet == NULL) { + talloc_free(tmp_ctx); + return; + } + + /* parse the request */ + status = ndr_pull_struct_blob(&blob, packet, packet, + (ndr_pull_flags_fn_t)ndr_pull_nbt_dgram_packet); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(2,("Failed to parse incoming NBT DGRAM packet - %s\n", + nt_errstr(status))); + talloc_free(tmp_ctx); + return; + } + + NDR_PRINT_DEBUG(nbt_dgram_packet, packet); + + talloc_free(tmp_ctx); +} + + +/* + handle fd events on a nbt_dgram_socket +*/ +static void dgm_socket_handler(struct event_context *ev, struct fd_event *fde, + uint16_t flags, void *private) +{ + struct nbt_dgram_socket *dgmsock = talloc_get_type(private, + struct nbt_dgram_socket); + if (flags & EVENT_FD_WRITE) { + /* nothing at the moment */ + } else if (flags & EVENT_FD_READ) { + dgm_socket_recv(dgmsock); + } +} + +/* + initialise a nbt_dgram_socket. The event_ctx is optional, if provided + then operations will use that event context +*/ +struct nbt_dgram_socket *nbt_dgram_socket_init(TALLOC_CTX *mem_ctx, + struct event_context *event_ctx) +{ + struct nbt_dgram_socket *dgmsock; + NTSTATUS status; + + dgmsock = talloc(mem_ctx, struct nbt_dgram_socket); + if (dgmsock == NULL) goto failed; + + if (event_ctx == NULL) { + dgmsock->event_ctx = event_context_init(dgmsock); + } else { + dgmsock->event_ctx = talloc_reference(dgmsock, event_ctx); + } + if (dgmsock->event_ctx == NULL) goto failed; + + status = socket_create("ip", SOCKET_TYPE_DGRAM, &dgmsock->sock, 0); + if (!NT_STATUS_IS_OK(status)) goto failed; + + socket_set_option(dgmsock->sock, "SO_BROADCAST", "1"); + + talloc_steal(dgmsock, dgmsock->sock); + + dgmsock->fde = event_add_fd(dgmsock->event_ctx, dgmsock, + socket_get_fd(dgmsock->sock), 0, + dgm_socket_handler, dgmsock); + + return dgmsock; + +failed: + talloc_free(dgmsock); + return NULL; +} + + +/* + setup a handler for incoming requests +*/ +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) +{ + dgmsock->incoming.handler = handler; + dgmsock->incoming.private = private; + EVENT_FD_READABLE(dgmsock->fde); + return NT_STATUS_OK; +} diff --git a/source4/libcli/dgram/libdgram.h b/source4/libcli/dgram/libdgram.h new file mode 100644 index 0000000000..6ead6dccf0 --- /dev/null +++ b/source4/libcli/dgram/libdgram.h @@ -0,0 +1,41 @@ +/* + Unix SMB/CIFS implementation. + + a raw async NBT DGRAM library + + 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 "librpc/gen_ndr/ndr_nbt.h" + +/* + context structure for operations on dgram packets +*/ +struct nbt_dgram_socket { + struct socket_context *sock; + struct event_context *event_ctx; + + /* the fd event */ + struct fd_event *fde; + + /* what to do with incoming request packets */ + struct { + void (*handler)(struct nbt_dgram_socket *, struct nbt_dgram_packet *, + const char *, int ); + void *private; + } incoming; +}; diff --git a/source4/librpc/idl/nbt.idl b/source4/librpc/idl/nbt.idl index 04fe0c4f90..4d12dd02d0 100644 --- a/source4/librpc/idl/nbt.idl +++ b/source4/librpc/idl/nbt.idl @@ -183,4 +183,66 @@ interface nbt nbt_res_rec additional[arcount]; [flag(NDR_REMAINING)] DATA_BLOB padding; } nbt_name_packet; + + + /* + NBT DGRAM packets (UDP/138) + */ + + typedef [enum8bit] enum { + DGRAM_DIRECT_UNIQUE = 0x10, + DGRAM_DIRECT_GROUP = 0x11, + DGRAM_BCAST = 0x12, + DGRAM_ERROR = 0x13, + DGRAM_QUERY = 0x14, + DGRAM_QUERY_POSITIVE = 0x15, + DGRAM_QUERY_NEGATIVE = 0x16 + } dgram_msg_type; + + typedef [bitmap8bit] bitmap { + DGRAM_FLAG_MORE = 0x80, + DGRAM_FLAG_FIRST = 0x40, + DGRAM_FLAG_NODE_TYPE = 0x30 + } dgram_flags; + + typedef [enum8bit] enum { + DGRAM_NODE_B = 0x00, + DGRAM_NODE_P = 0x10, + DGRAM_NODE_M = 0x20, + DGRAM_NODE_NBDD = 0x30 + } dgram_node_type; + + /* a dgram_message is the main dgram body in general use */ + typedef struct { + uint16 length; + uint16 offset; + nbt_name source_name; + nbt_name dest_name; + [flag(NDR_REMAINING)] DATA_BLOB data; + } dgram_message; + + typedef [enum8bit] enum { + DGRAM_ERROR_NAME_NOT_PRESENT = 0x82, + DGRAM_ERROR_INVALID_SOURCE = 0x83, + DGRAM_ERROR_INVALID_DEST = 0x84 + } 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_ERROR)] dgram_err_code error; + [case(DGRAM_QUERY)] nbt_name dest_name; + [case(DGRAM_QUERY_POSITIVE)] nbt_name dest_name; + [case(DGRAM_QUERY_NEGATIVE)] nbt_name dest_name; + } dgram_data; + + typedef [flag(NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct { + dgram_msg_type msg_type; + dgram_flags flags; + uint16 dgram_id; + ipv4address source; + uint16 src_port; + [switch_is(msg_type)] dgram_data data; + } nbt_dgram_packet; } diff --git a/source4/nbt_server/interfaces.c b/source4/nbt_server/interfaces.c index bc01ac6d99..dfd4538321 100644 --- a/source4/nbt_server/interfaces.c +++ b/source4/nbt_server/interfaces.c @@ -63,6 +63,16 @@ static void nbtd_request_handler(struct nbt_name_socket *nbtsock, } +/* + receive an incoming dgram request +*/ +static void dgram_request_handler(struct nbt_dgram_socket *dgmsock, + struct nbt_dgram_packet *packet, + const char *src_address, int src_port) +{ +} + + /* find a registered name on an interface @@ -93,7 +103,6 @@ static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv, { struct nbtd_interface *iface; NTSTATUS status; - struct nbt_name_socket *bcast_nbtsock; /* we actually create two sockets. One listens on the broadcast address @@ -113,6 +122,10 @@ static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv, iface->names = NULL; if (strcmp(netmask, "0.0.0.0") != 0) { + struct nbt_name_socket *bcast_nbtsock; + struct nbt_dgram_socket *bcast_dgmsock; + + /* listen for broadcasts on port 137 */ bcast_nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx); NT_STATUS_HAVE_NO_MEMORY(bcast_nbtsock); @@ -125,10 +138,26 @@ static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv, } nbt_set_incoming_handler(bcast_nbtsock, nbtd_request_handler, iface); + + + /* listen for broadcasts on port 138 */ + bcast_dgmsock = nbt_dgram_socket_init(iface, nbtsrv->task->event_ctx); + NT_STATUS_HAVE_NO_MEMORY(bcast_dgmsock); + + status = socket_listen(bcast_dgmsock->sock, bcast, lp_dgram_port(), 0, 0); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Failed to bind to %s:%d - %s\n", + bcast, lp_dgram_port(), nt_errstr(status))); + talloc_free(iface); + return status; + } + + dgram_set_incoming_handler(bcast_dgmsock, dgram_request_handler, iface); } + /* listen for unicasts on port 137 */ iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx); - NT_STATUS_HAVE_NO_MEMORY(iface->ip_address); + NT_STATUS_HAVE_NO_MEMORY(iface->nbtsock); status = socket_listen(iface->nbtsock->sock, bind_address, lp_nbt_port(), 0, 0); if (!NT_STATUS_IS_OK(status)) { @@ -137,9 +166,22 @@ static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv, talloc_free(iface); return status; } - nbt_set_incoming_handler(iface->nbtsock, nbtd_request_handler, iface); + + /* listen for unicasts on port 138 */ + iface->dgmsock = nbt_dgram_socket_init(iface, nbtsrv->task->event_ctx); + NT_STATUS_HAVE_NO_MEMORY(iface->dgmsock); + + status = socket_listen(iface->dgmsock->sock, bind_address, lp_dgram_port(), 0, 0); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Failed to bind to %s:%d - %s\n", + address, lp_dgram_port(), nt_errstr(status))); + talloc_free(iface); + return status; + } + dgram_set_incoming_handler(iface->dgmsock, dgram_request_handler, iface); + if (strcmp(netmask, "0.0.0.0") == 0) { DLIST_ADD(nbtsrv->bcast_interface, iface); } else { diff --git a/source4/nbt_server/nbt_server.h b/source4/nbt_server/nbt_server.h index 6a7b14a546..e2b8584f5a 100644 --- a/source4/nbt_server/nbt_server.h +++ b/source4/nbt_server/nbt_server.h @@ -21,6 +21,7 @@ */ #include "libcli/nbt/libnbt.h" +#include "libcli/dgram/libdgram.h" /* a list of our registered names on each interface @@ -47,6 +48,7 @@ struct nbtd_interface { const char *bcast_address; const char *netmask; struct nbt_name_socket *nbtsock; + struct nbt_dgram_socket *dgmsock; struct nbtd_iface_name *names; }; diff --git a/source4/nbt_server/register.c b/source4/nbt_server/register.c index bec316cdea..cd39ef4769 100644 --- a/source4/nbt_server/register.c +++ b/source4/nbt_server/register.c @@ -27,6 +27,7 @@ #include "smbd/service_task.h" #include "libcli/raw/libcliraw.h" #include "libcli/composite/composite.h" +#include "librpc/gen_ndr/ndr_samr.h" static void nbtd_start_refresh_timer(struct nbtd_iface_name *iname); @@ -264,6 +265,17 @@ void nbtd_register_names(struct nbtd_server *nbtsrv) aliases++; } + switch (lp_server_role()) { + case ROLE_DOMAIN_PDC: + nbtd_register_name(nbtsrv, lp_workgroup(), NBT_NAME_PDC, nb_flags); + nbtd_register_name(nbtsrv, lp_workgroup(), NBT_NAME_LOGON, nb_flags); + break; + case ROLE_DOMAIN_BDC: + nbtd_register_name(nbtsrv, lp_workgroup(), NBT_NAME_LOGON, nb_flags); + default: + break; + } + nb_flags |= NBT_NM_GROUP; nbtd_register_name(nbtsrv, lp_workgroup(), NBT_NAME_CLIENT, nb_flags); diff --git a/source4/param/loadparm.c b/source4/param/loadparm.c index 33026dd9e0..29da770d47 100644 --- a/source4/param/loadparm.c +++ b/source4/param/loadparm.c @@ -236,6 +236,7 @@ typedef struct int iLockSpinCount; int iLockSpinTime; int nbt_port; + int dgram_port; char *socket_options; BOOL bDNSproxy; BOOL bWINSsupport; @@ -617,6 +618,7 @@ static struct parm_struct parm_table[] = { {"smb ports", P_LIST, P_GLOBAL, &Globals.smb_ports, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, {"nbt port", P_INTEGER, P_GLOBAL, &Globals.nbt_port, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, + {"dgram port", P_INTEGER, P_GLOBAL, &Globals.dgram_port, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, {"large readwrite", P_BOOL, P_GLOBAL, &Globals.bLargeReadwrite, NULL, NULL, FLAG_DEVELOPER}, {"max protocol", P_ENUM, P_GLOBAL, &Globals.maxprotocol, NULL, enum_protocol, FLAG_DEVELOPER}, {"min protocol", P_ENUM, P_GLOBAL, &Globals.minprotocol, NULL, enum_protocol, FLAG_DEVELOPER}, @@ -1051,6 +1053,7 @@ static void init_globals(void) do_parameter("smb ports", SMB_PORTS); do_parameter("nbt port", "137"); + do_parameter("dgram port", "138"); do_parameter("nt status support", "True"); @@ -1152,6 +1155,7 @@ static const char *lp_string(const char *s) FN_GLOBAL_LIST(lp_smb_ports, &Globals.smb_ports) FN_GLOBAL_INTEGER(lp_nbt_port, &Globals.nbt_port) +FN_GLOBAL_INTEGER(lp_dgram_port, &Globals.dgram_port) FN_GLOBAL_STRING(lp_dos_charset, &Globals.dos_charset) FN_GLOBAL_STRING(lp_unix_charset, &Globals.unix_charset) FN_GLOBAL_STRING(lp_display_charset, &Globals.display_charset) |