1
0
mirror of https://github.com/samba-team/samba.git synced 2025-12-03 04:23:50 +03:00

r5358: - added initial WINS server code. It passes most of the NBT-WINS test, but doesn't yet

do secure server WACK responses

- added a ldap_string_to_time() function, for converting a LDAP
  formatted time to a time_t
This commit is contained in:
Andrew Tridgell
2005-02-12 11:33:42 +00:00
committed by Gerald (Jerry) Carter
parent 18fb48204f
commit 9aa3313b3f
11 changed files with 424 additions and 34 deletions

View File

@@ -173,7 +173,9 @@ struct stream_server_ops;
struct nbtd_server;
struct nbtd_interface;
struct wins_server;
struct mutex_ops;
struct ads_struct;

View File

@@ -292,9 +292,9 @@ char *http_timestring(TALLOC_CTX *mem_ctx, time_t t)
return buf;
}
/***************************************************************************
/*
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
****************************************************************************/

View File

@@ -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),

View File

@@ -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,

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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;
};

View File

@@ -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,
void nbtd_name_registration_reply(struct nbt_name_socket *nbtsock,
struct nbt_name_packet *request_packet,
const char *src_address, int src_port)
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);

178
source/nbt_server/winsdb.c Normal file
View File

@@ -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;
}

View File

@@ -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;
};

View File

@@ -22,28 +22,121 @@
#include "includes.h"
#include "nbt_server/nbt_server.h"
#include "nbt_server/winsdb.h"
#include "system/time.h"
static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock,
/*
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)
{
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;
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)
{
nbtd_negative_name_registration_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;
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)
{
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;
}
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);
return NT_STATUS_OK;
nbtsrv->winssrv->max_ttl = lp_max_wins_ttl();
nbtsrv->winssrv->min_ttl = lp_min_wins_ttl();
return winsdb_init(nbtsrv->winssrv);
}