summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/include/structs.h2
-rw-r--r--source4/lib/time.c28
-rw-r--r--source4/libcli/nbt/nbtname.c4
-rw-r--r--source4/librpc/idl/nbt.idl1
-rw-r--r--source4/nbt_server/config.mk5
-rw-r--r--source4/nbt_server/defense.c4
-rw-r--r--source4/nbt_server/nbt_server.h3
-rw-r--r--source4/nbt_server/packet.c58
-rw-r--r--source4/nbt_server/winsdb.c178
-rw-r--r--source4/nbt_server/winsdb.h46
-rw-r--r--source4/nbt_server/winsserver.c127
11 files changed, 423 insertions, 33 deletions
diff --git a/source4/include/structs.h b/source4/include/structs.h
index 61c1f4211c..32a30d9d9d 100644
--- a/source4/include/structs.h
+++ b/source4/include/structs.h
@@ -173,7 +173,9 @@ struct stream_server_ops;
struct nbtd_server;
struct nbtd_interface;
+struct wins_server;
struct mutex_ops;
struct ads_struct;
+
diff --git a/source4/lib/time.c b/source4/lib/time.c
index 7a4059f646..67397e953a 100644
--- a/source4/lib/time.c
+++ b/source4/lib/time.c
@@ -292,9 +292,9 @@ char *http_timestring(TALLOC_CTX *mem_ctx, time_t t)
return buf;
}
-/***************************************************************************
-return a LDAP time string
- ***************************************************************************/
+/*
+ return a LDAP time string
+*/
char *ldap_timestring(TALLOC_CTX *mem_ctx, time_t t)
{
struct tm *tm = gmtime(&t);
@@ -311,6 +311,28 @@ char *ldap_timestring(TALLOC_CTX *mem_ctx, time_t t)
tm->tm_sec);
}
+
+/*
+ convert a LDAP time string to a time_t. Return 0 if unable to convert
+*/
+time_t ldap_string_to_time(const char *s)
+{
+ struct tm tm;
+
+ if (s == NULL) return 0;
+
+ ZERO_STRUCT(tm);
+ if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
+ return 0;
+ }
+ tm.tm_year -= 1900;
+ tm.tm_mon -= 1;
+
+ return timegm(&tm);
+}
+
/****************************************************************************
Return the date and time as a string
****************************************************************************/
diff --git a/source4/libcli/nbt/nbtname.c b/source4/libcli/nbt/nbtname.c
index adc66980c4..b937d0aa26 100644
--- a/source4/libcli/nbt/nbtname.c
+++ b/source4/libcli/nbt/nbtname.c
@@ -359,10 +359,10 @@ static const char *nbt_hex_encode(TALLOC_CTX *mem_ctx, const char *s)
/*
form a string for a NBT name
*/
-const char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name)
+char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name)
{
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
- const char *ret;
+ char *ret;
if (name->scope) {
ret = talloc_asprintf(mem_ctx, "%s<%02x>-%s",
nbt_hex_encode(tmp_ctx, name->name),
diff --git a/source4/librpc/idl/nbt.idl b/source4/librpc/idl/nbt.idl
index 859cecd593..04fe0c4f90 100644
--- a/source4/librpc/idl/nbt.idl
+++ b/source4/librpc/idl/nbt.idl
@@ -38,6 +38,7 @@ interface nbt
/* rcode values */
typedef enum {
+ NBT_RCODE_OK = 0x0,
NBT_RCODE_FMT = 0x1,
NBT_RCODE_SVR = 0x2,
NBT_RCODE_NAM = 0x3,
diff --git a/source4/nbt_server/config.mk b/source4/nbt_server/config.mk
index 8054ebc4de..12d0a09b6b 100644
--- a/source4/nbt_server/config.mk
+++ b/source4/nbt_server/config.mk
@@ -10,10 +10,11 @@ ADD_OBJ_FILES = \
nbt_server/register.o \
nbt_server/query.o \
nbt_server/nodestatus.o \
- nbt_server/winsserver.o \
nbt_server/winsclient.o \
nbt_server/defense.o \
- nbt_server/packet.o
+ nbt_server/packet.o \
+ nbt_server/winsserver.o \
+ nbt_server/winsdb.o
REQUIRED_SUBSYSTEMS = \
LIBCLI_NBT
# End SUBSYSTEM SMB
diff --git a/source4/nbt_server/defense.c b/source4/nbt_server/defense.c
index 00e0e740af..c59877e4b7 100644
--- a/source4/nbt_server/defense.c
+++ b/source4/nbt_server/defense.c
@@ -60,8 +60,8 @@ void nbtd_request_defense(struct nbt_name_socket *nbtsock,
DEBUG(2,("Defending name %s on %s against %s\n",
nbt_name_string(packet, name),
iface->bcast_address, src_address));
- nbtd_negative_name_registration_reply(nbtsock, packet,
- src_address, src_port);
+ nbtd_name_registration_reply(nbtsock, packet,
+ src_address, src_port, NBT_RCODE_ACT);
} else {
nbtd_winsserver_request(nbtsock, packet, src_address, src_port);
}
diff --git a/source4/nbt_server/nbt_server.h b/source4/nbt_server/nbt_server.h
index 309c01a639..a698ebf1a0 100644
--- a/source4/nbt_server/nbt_server.h
+++ b/source4/nbt_server/nbt_server.h
@@ -67,8 +67,7 @@ struct nbtd_server {
our names with a WINS server */
struct nbtd_interface *wins_interface;
- /* wins server database handle, if configured */
- struct ldb_wrap *wins_db;
+ struct wins_server *winssrv;
};
diff --git a/source4/nbt_server/packet.c b/source4/nbt_server/packet.c
index e6eec27fdc..6383909149 100644
--- a/source4/nbt_server/packet.c
+++ b/source4/nbt_server/packet.c
@@ -178,11 +178,12 @@ failed:
}
/*
- send a name defense reply
+ send a name registration reply
*/
-void nbtd_negative_name_registration_reply(struct nbt_name_socket *nbtsock,
- struct nbt_name_packet *request_packet,
- const char *src_address, int src_port)
+void nbtd_name_registration_reply(struct nbt_name_socket *nbtsock,
+ struct nbt_name_packet *request_packet,
+ const char *src_address, int src_port,
+ uint8_t rcode)
{
struct nbt_name_packet *packet;
struct nbt_name *name = &request_packet->questions[0].name;
@@ -198,7 +199,7 @@ void nbtd_negative_name_registration_reply(struct nbt_name_socket *nbtsock,
NBT_FLAG_AUTHORITIVE |
NBT_FLAG_RECURSION_DESIRED |
NBT_FLAG_RECURSION_AVAIL |
- NBT_RCODE_ACT;
+ rcode;
packet->answers = talloc_array(packet, struct nbt_res_rec, 1);
if (packet->answers == NULL) goto failed;
@@ -206,10 +207,53 @@ void nbtd_negative_name_registration_reply(struct nbt_name_socket *nbtsock,
packet->answers[0].name = *name;
packet->answers[0].rr_type = NBT_QTYPE_NETBIOS;
packet->answers[0].rr_class = NBT_QCLASS_IP;
- packet->answers[0].ttl = 0;
+ packet->answers[0].ttl = request_packet->additional[0].ttl;
packet->answers[0].rdata = request_packet->additional[0].rdata;
- DEBUG(7,("Sending negative name registration reply for %s to %s:%d\n",
+ DEBUG(7,("Sending %s name registration reply for %s to %s:%d\n",
+ rcode==0?"positive":"negative",
+ nbt_name_string(packet, name), src_address, src_port));
+
+ nbt_name_reply_send(nbtsock, src_address, src_port, packet);
+
+failed:
+ talloc_free(packet);
+}
+
+
+/*
+ send a name release reply
+*/
+void nbtd_name_release_reply(struct nbt_name_socket *nbtsock,
+ struct nbt_name_packet *request_packet,
+ const char *src_address, int src_port,
+ uint8_t rcode)
+{
+ struct nbt_name_packet *packet;
+ struct nbt_name *name = &request_packet->questions[0].name;
+
+ packet = talloc_zero(nbtsock, struct nbt_name_packet);
+ if (packet == NULL) return;
+
+ packet->name_trn_id = request_packet->name_trn_id;
+ packet->ancount = 1;
+ packet->operation =
+ NBT_FLAG_REPLY |
+ NBT_OPCODE_RELEASE |
+ NBT_FLAG_AUTHORITIVE |
+ rcode;
+
+ packet->answers = talloc_array(packet, struct nbt_res_rec, 1);
+ if (packet->answers == NULL) goto failed;
+
+ packet->answers[0].name = *name;
+ packet->answers[0].rr_type = NBT_QTYPE_NETBIOS;
+ packet->answers[0].rr_class = NBT_QCLASS_IP;
+ packet->answers[0].ttl = request_packet->additional[0].ttl;
+ packet->answers[0].rdata = request_packet->additional[0].rdata;
+
+ DEBUG(7,("Sending %s name release reply for %s to %s:%d\n",
+ rcode==0?"positive":"negative",
nbt_name_string(packet, name), src_address, src_port));
nbt_name_reply_send(nbtsock, src_address, src_port, packet);
diff --git a/source4/nbt_server/winsdb.c b/source4/nbt_server/winsdb.c
new file mode 100644
index 0000000000..bb7ce49b9b
--- /dev/null
+++ b/source4/nbt_server/winsdb.c
@@ -0,0 +1,178 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ WINS database routines
+
+ 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 "nbt_server/nbt_server.h"
+#include "nbt_server/winsdb.h"
+#include "lib/ldb/include/ldb.h"
+#include "db_wrap.h"
+
+/*
+ load a WINS entry from the database
+*/
+struct winsdb_record *winsdb_load(struct wins_server *winssrv,
+ struct nbt_name *name, TALLOC_CTX *mem_ctx)
+{
+ struct ldb_message **res = NULL;
+ int ret;
+ struct winsdb_record *rec;
+ struct ldb_message_element *el;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ const char *expr;
+ int i;
+
+ expr = talloc_asprintf(tmp_ctx, "dn=%s", nbt_name_string(tmp_ctx, name));
+ if (expr == NULL) goto failed;
+
+ /* find the record in the WINS database */
+ ret = ldb_search(winssrv->wins_db->ldb, NULL, LDB_SCOPE_ONELEVEL, expr, NULL, &res);
+ if (res != NULL) {
+ talloc_steal(tmp_ctx, res);
+ }
+ if (ret != 1) goto failed;
+
+ rec = talloc(tmp_ctx, struct winsdb_record);
+ if (rec == NULL) goto failed;
+
+ /* parse it into a more convenient winsdb_record structure */
+ rec->name = name;
+ rec->state = ldb_msg_find_int(res[0], "active", WINS_REC_RELEASED);
+ rec->nb_flags = ldb_msg_find_int(res[0], "nbFlags", 0);
+ rec->expire_time = ldap_string_to_time(ldb_msg_find_string(res[0], "expires", NULL));
+ rec->registered_by = ldb_msg_find_string(res[0], "registeredBy", NULL);
+ talloc_steal(rec, rec->registered_by);
+
+ el = ldb_msg_find_element(res[0], "address");
+ if (el == NULL) goto failed;
+
+ rec->addresses = talloc_array(rec, const char *, el->num_values+1);
+ if (rec->addresses == NULL) goto failed;
+
+ for (i=0;i<el->num_values;i++) {
+ rec->addresses[i] = talloc_steal(rec->addresses, el->values[i].data);
+ }
+ rec->addresses[i] = NULL;
+
+ talloc_steal(mem_ctx, rec);
+ talloc_free(tmp_ctx);
+ return rec;
+
+failed:
+ talloc_free(tmp_ctx);
+ return NULL;
+}
+
+
+/*
+ form a ldb_message from a winsdb_record
+*/
+static struct ldb_message *winsdb_message(struct wins_server *winssrv,
+ struct winsdb_record *rec, TALLOC_CTX *mem_ctx)
+{
+ int i, ret=0;
+ struct ldb_context *ldb = winssrv->wins_db->ldb;
+ struct ldb_message *msg = ldb_msg_new(mem_ctx);
+ if (msg == NULL) goto failed;
+
+ msg->dn = nbt_name_string(msg, rec->name);
+ if (msg->dn == NULL) goto failed;
+ ret |= ldb_msg_add_fmt(ldb, msg, "active", "%u", rec->state);
+ ret |= ldb_msg_add_fmt(ldb, msg, "nbFlags", "0x%04x", rec->nb_flags);
+ ret |= ldb_msg_add_string(ldb, msg, "registeredBy", rec->registered_by);
+ ret |= ldb_msg_add_string(ldb, msg, "expires",
+ ldap_timestring(msg, rec->expire_time));
+ for (i=0;rec->addresses[i];i++) {
+ ret |= ldb_msg_add_string(ldb, msg, "address", rec->addresses[i]);
+ }
+ if (ret != 0) goto failed;
+ return msg;
+
+failed:
+ talloc_free(msg);
+ return NULL;
+}
+
+/*
+ save a WINS record into the database
+*/
+uint8_t winsdb_add(struct wins_server *winssrv, struct winsdb_record *rec)
+{
+ struct ldb_context *ldb = winssrv->wins_db->ldb;
+ struct ldb_message *msg;
+ TALLOC_CTX *tmp_ctx = talloc_new(winssrv);
+ int ret;
+
+ msg = winsdb_message(winssrv, rec, tmp_ctx);
+ if (msg == NULL) goto failed;
+ ret = ldb_add(ldb, msg);
+ if (ret != 0) goto failed;
+
+ talloc_free(tmp_ctx);
+ return NBT_RCODE_OK;
+
+failed:
+ talloc_free(tmp_ctx);
+ return NBT_RCODE_SVR;
+}
+
+
+/*
+ modify a WINS record in the database
+*/
+uint8_t winsdb_modify(struct wins_server *winssrv, struct winsdb_record *rec)
+{
+ struct ldb_context *ldb = winssrv->wins_db->ldb;
+ struct ldb_message *msg;
+ TALLOC_CTX *tmp_ctx = talloc_new(winssrv);
+ int ret;
+ int i;
+
+ msg = winsdb_message(winssrv, rec, tmp_ctx);
+ if (msg == NULL) goto failed;
+
+ for (i=0;i<msg->num_elements;i++) {
+ msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
+ }
+
+ ret = ldb_modify(ldb, msg);
+ if (ret != 0) goto failed;
+
+ talloc_free(tmp_ctx);
+ return NBT_RCODE_OK;
+
+failed:
+ talloc_free(tmp_ctx);
+ return NBT_RCODE_SVR;
+}
+
+/*
+ connect to the WINS database
+*/
+NTSTATUS winsdb_init(struct wins_server *winssrv)
+{
+ winssrv->wins_db = ldb_wrap_connect(winssrv, lp_wins_url(), 0, NULL);
+ if (winssrv->wins_db == NULL) {
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/nbt_server/winsdb.h b/source4/nbt_server/winsdb.h
new file mode 100644
index 0000000000..72aeb8ef78
--- /dev/null
+++ b/source4/nbt_server/winsdb.h
@@ -0,0 +1,46 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ WINS server structures
+
+ 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.
+*/
+
+enum wins_record_state {
+ WINS_REC_RELEASED=0,
+ WINS_REC_ACTIVE=1
+};
+
+/*
+ each record in the database contains the following information
+*/
+struct winsdb_record {
+ struct nbt_name *name;
+ uint16_t nb_flags;
+ enum wins_record_state state;
+ time_t expire_time;
+ const char *registered_by;
+ const char **addresses;
+};
+
+struct wins_server {
+ /* wins server database handle */
+ struct ldb_wrap *wins_db;
+
+ uint32_t min_ttl;
+ uint32_t max_ttl;
+};
diff --git a/source4/nbt_server/winsserver.c b/source4/nbt_server/winsserver.c
index 22cfee415c..b59a1c9fa3 100644
--- a/source4/nbt_server/winsserver.c
+++ b/source4/nbt_server/winsserver.c
@@ -22,28 +22,121 @@
#include "includes.h"
#include "nbt_server/nbt_server.h"
+#include "nbt_server/winsdb.h"
+#include "system/time.h"
+/*
+ register a new name with WINS
+*/
+static uint8_t wins_register_new(struct nbt_name_socket *nbtsock,
+ struct nbt_name_packet *packet,
+ const char *src_address, int src_port)
+{
+ struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
+ struct nbtd_interface);
+ struct wins_server *winssrv = iface->nbtsrv->winssrv;
+ struct nbt_name *name = &packet->questions[0].name;
+ uint32_t ttl = packet->additional[0].ttl;
+ struct winsdb_record rec;
+
+ ttl = MIN(ttl, winssrv->max_ttl);
+ ttl = MAX(ttl, winssrv->min_ttl);
+
+ rec.name = name;
+ rec.nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
+ rec.state = WINS_REC_ACTIVE;
+ rec.expire_time = time(NULL) + ttl;
+ rec.registered_by = src_address;
+ rec.addresses = str_list_make(packet,
+ packet->additional[0].rdata.netbios.addresses[0].ipaddr,
+ NULL);
+
+ return winsdb_add(winssrv, &rec);
+}
+/*
+ register a name
+*/
+static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
+ struct nbt_name_packet *packet,
+ const char *src_address, int src_port)
+{
+ struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
+ struct nbtd_interface);
+ struct wins_server *winssrv = iface->nbtsrv->winssrv;
+ struct nbt_name *name = &packet->questions[0].name;
+ struct winsdb_record *rec;
+ uint8_t rcode = 0;
+
+ rec = winsdb_load(winssrv, name, packet);
+ if (rec == NULL) {
+ rcode = wins_register_new(nbtsock, packet, src_address, src_port);
+ } else if (rec->state != WINS_REC_ACTIVE) {
+ uint32_t ttl = packet->additional[0].ttl;
+ ttl = MIN(ttl, winssrv->max_ttl);
+ ttl = MAX(ttl, winssrv->min_ttl);
+ rec->nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
+ rec->state = WINS_REC_ACTIVE;
+ rec->expire_time = time(NULL) + ttl;
+ rec->registered_by = src_address;
+ rec->addresses = str_list_make(packet,
+ packet->additional[0].rdata.netbios.addresses[0].ipaddr,
+ NULL);
+ winsdb_modify(winssrv, rec);
+ } else {
+ rcode = NBT_RCODE_ACT;
+ }
+
+ nbtd_name_registration_reply(nbtsock, packet, src_address, src_port, rcode);
+}
+
+
+
+/*
+ query a name
+*/
static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock,
struct nbt_name_packet *packet,
const char *src_address, int src_port)
{
- nbtd_negative_name_query_reply(nbtsock, packet, src_address, src_port);
-}
+ struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
+ struct nbtd_interface);
+ struct wins_server *winssrv = iface->nbtsrv->winssrv;
+ struct nbt_name *name = &packet->questions[0].name;
+ struct winsdb_record *rec;
+
+ rec = winsdb_load(winssrv, name, packet);
+ if (rec == NULL || rec->state != WINS_REC_ACTIVE) {
+ nbtd_negative_name_query_reply(nbtsock, packet, src_address, src_port);
+ return;
+ }
-static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
- struct nbt_name_packet *packet,
- const char *src_address, int src_port)
-{
- nbtd_negative_name_registration_reply(nbtsock, packet, src_address, src_port);
+ nbtd_name_query_reply(nbtsock, packet, src_address, src_port, name,
+ 0, rec->nb_flags, rec->addresses);
}
-
+/*
+ release a name
+*/
static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
struct nbt_name_packet *packet,
const char *src_address, int src_port)
{
+ struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
+ struct nbtd_interface);
+ struct wins_server *winssrv = iface->nbtsrv->winssrv;
+ struct nbt_name *name = &packet->questions[0].name;
+ struct winsdb_record *rec;
+
+ rec = winsdb_load(winssrv, name, packet);
+ if (rec != NULL && rec->state == WINS_REC_ACTIVE) {
+ rec->state = WINS_REC_RELEASED;
+ winsdb_modify(winssrv, rec);
+ }
+
+ /* we match w2k3 by always giving a positive reply to name releases. */
+ nbtd_name_release_reply(nbtsock, packet, src_address, src_port, NBT_RCODE_OK);
}
@@ -54,7 +147,10 @@ void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
struct nbt_name_packet *packet,
const char *src_address, int src_port)
{
- if (packet->operation & NBT_FLAG_BROADCAST) {
+ struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
+ struct nbtd_interface);
+ struct wins_server *winssrv = iface->nbtsrv->winssrv;
+ if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
return;
}
@@ -83,14 +179,15 @@ void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
{
if (!lp_wins_support()) {
- nbtsrv->wins_db = NULL;
+ nbtsrv->winssrv = NULL;
return NT_STATUS_OK;
}
- nbtsrv->wins_db = ldb_wrap_connect(nbtsrv, lp_wins_url(), 0, NULL);
- if (nbtsrv->wins_db == NULL) {
- return NT_STATUS_INTERNAL_DB_ERROR;
- }
+ nbtsrv->winssrv = talloc(nbtsrv, struct wins_server);
+ NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
+
+ nbtsrv->winssrv->max_ttl = lp_max_wins_ttl();
+ nbtsrv->winssrv->min_ttl = lp_min_wins_ttl();
- return NT_STATUS_OK;
+ return winsdb_init(nbtsrv->winssrv);
}