summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/libcli/dgram/dgramsocket.c153
-rw-r--r--source4/libcli/dgram/libdgram.h41
-rw-r--r--source4/librpc/idl/nbt.idl62
-rw-r--r--source4/nbt_server/interfaces.c48
-rw-r--r--source4/nbt_server/nbt_server.h2
-rw-r--r--source4/nbt_server/register.c12
-rw-r--r--source4/param/loadparm.c4
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)