wmi-1.3.16 from opsview.com

This commit is contained in:
Are Casilla
2019-02-16 00:16:52 +01:00
parent 163fdd3d1b
commit 17b3af2911
2146 changed files with 678824 additions and 0 deletions
@@ -0,0 +1,98 @@
/*
Unix SMB/CIFS implementation.
wins server dns proxy
Copyright (C) Stefan Metzmacher 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/wins/winsdb.h"
#include "nbt_server/wins/winsserver.h"
#include "system/time.h"
#include "libcli/composite/composite.h"
#include "smbd/service_task.h"
#include "libcli/resolve/resolve.h"
struct wins_dns_proxy_state {
struct nbt_name_socket *nbtsock;
struct nbt_name_packet *packet;
struct socket_address *src;
};
static void nbtd_wins_dns_proxy_handler(struct composite_context *creq)
{
NTSTATUS status;
struct wins_dns_proxy_state *s = talloc_get_type(creq->async.private_data,
struct wins_dns_proxy_state);
struct nbt_name *name = &s->packet->questions[0].name;
const char *address;
const char **addresses;
uint16_t nb_flags = 0; /* TODO: ... */
status = resolve_name_recv(creq, s->packet, &address);
if (!NT_STATUS_IS_OK(status)) {
goto notfound;
}
addresses = str_list_add(NULL, address);
talloc_steal(s->packet, addresses);
if (!addresses) goto notfound;
nbtd_name_query_reply(s->nbtsock, s->packet, s->src, name,
0, nb_flags, addresses);
return;
notfound:
nbtd_negative_name_query_reply(s->nbtsock, s->packet, s->src);
}
/*
dns proxy query a name
*/
void nbtd_wins_dns_proxy_query(struct nbt_name_socket *nbtsock,
struct nbt_name_packet *packet,
struct socket_address *src)
{
struct nbt_name *name = &packet->questions[0].name;
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
struct nbtd_interface);
struct wins_dns_proxy_state *s;
struct composite_context *creq;
const char *methods[] = {
"host",
NULL
};
s = talloc(nbtsock, struct wins_dns_proxy_state);
if (!s) goto failed;
s->nbtsock = nbtsock;
s->packet = talloc_steal(s, packet);
s->src = src;
if (!talloc_reference(s, src)) {
goto failed;
}
creq = resolve_name_send(name, iface->nbtsrv->task->event_ctx, methods);
if (!creq) goto failed;
creq->async.fn = nbtd_wins_dns_proxy_handler;
creq->async.private_data= s;
return;
failed:
nbtd_negative_name_query_reply(nbtsock, packet, src);
}
+95
View File
@@ -0,0 +1,95 @@
/*
Unix SMB/CIFS implementation.
wins hook feature, we run a specified script
which can then do some custom actions
Copyright (C) Stefan Metzmacher 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/wins/winsdb.h"
#include "system/filesys.h"
static const char *wins_hook_action_string(enum wins_hook_action action)
{
switch (action) {
case WINS_HOOK_ADD: return "add";
case WINS_HOOK_MODIFY: return "refresh";
case WINS_HOOK_DELETE: return "delete";
}
return "unknown";
}
void wins_hook(struct winsdb_handle *h, const struct winsdb_record *rec, enum wins_hook_action action)
{
const char *script = lp_wins_hook();
uint32_t i, length;
int child;
char *cmd = NULL;
TALLOC_CTX *tmp_mem = NULL;
if (!script || !script[0]) return;
tmp_mem = talloc_new(h);
if (!tmp_mem) goto failed;
length = winsdb_addr_list_length(rec->addresses);
if (action == WINS_HOOK_MODIFY && length < 1) {
action = WINS_HOOK_DELETE;
}
cmd = talloc_asprintf(tmp_mem,
"%s %s %s %02x %ld",
script,
wins_hook_action_string(action),
rec->name->name,
rec->name->type,
rec->expire_time);
if (!cmd) goto failed;
for (i=0; rec->addresses[i]; i++) {
cmd = talloc_asprintf_append(cmd, " %s", rec->addresses[i]->address);
if (!cmd) goto failed;
}
DEBUG(10,("call wins hook '%s'\n", cmd));
/* signal handling in posix really sucks - doing this in a library
affects the whole app, but what else to do?? */
signal(SIGCHLD, SIG_IGN);
child = fork();
if (child == (pid_t)-1) {
goto failed;
}
if (child == 0) {
/* TODO: close file handles */
execl("/bin/sh", "sh", "-c", cmd, NULL);
_exit(0);
}
talloc_free(tmp_mem);
return;
failed:
talloc_free(tmp_mem);
DEBUG(0,("FAILED: calling wins hook '%s'\n", script));
}
+124
View File
@@ -0,0 +1,124 @@
/*
ldb database module
Copyright (C) Stefan Metzmacher 2006
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.
*/
/*
* Name: ldb
*
* Component: ldb winsdb module
*
* Description: verify winsdb records before they're written to disk
*
* Author: Stefan Metzmacher
*/
#include "includes.h"
#include "nbt_server/nbt_server.h"
#include "nbt_server/wins/winsdb.h"
#include "lib/ldb/include/ldb.h"
#include "lib/ldb/include/ldb_errors.h"
#include "lib/ldb/include/ldb_private.h"
#include "system/network.h"
#include "lib/socket/netif.h"
static int wins_ldb_verify(struct ldb_module *module, struct ldb_request *req)
{
struct winsdb_handle *h = talloc_get_type(ldb_get_opaque(module->ldb, "winsdb_handle"),
struct winsdb_handle);
const struct ldb_message *msg;
switch (req->operation) {
case LDB_ADD:
msg = req->op.add.message;
break;
case LDB_MODIFY:
msg = req->op.mod.message;
break;
default:
return ldb_next_request(module, req);
}
/* do not manipulate our control entries */
if (ldb_dn_is_special(msg->dn)) {
return ldb_next_request(module, req);
}
if (!h) {
ldb_debug_set(module->ldb, LDB_DEBUG_FATAL, "%s", "WINS_LDB: INTERNAL ERROR: no winsdb_handle present!");
return LDB_ERR_OTHER;
}
switch (h->caller) {
case WINSDB_HANDLE_CALLER_NBTD:
case WINSDB_HANDLE_CALLER_WREPL:
/* we trust our nbt and wrepl code ... */
return ldb_next_request(module, req);
case WINSDB_HANDLE_CALLER_ADMIN:
ldb_debug(module->ldb, LDB_DEBUG_WARNING, "%s\n", "WINS_LDB: TODO verify add/modify for WINSDB_HANDLE_CALLER_ADMIN");
return ldb_next_request(module, req);
}
return LDB_ERR_OTHER;
}
static int wins_ldb_init(struct ldb_module *ctx)
{
struct winsdb_handle *h;
const char *owner;
ctx->private_data = NULL;
owner = lp_parm_string(-1, "winsdb", "local_owner");
if (!owner) {
owner = iface_n_ip(0);
if (!owner) {
owner = "0.0.0.0";
}
}
h = talloc(ctx, struct winsdb_handle);
if (!h) goto failed;
h->ldb = ctx->ldb;
h->caller = WINSDB_HANDLE_CALLER_ADMIN;
h->local_owner = talloc_strdup(h, owner);
if (!h->local_owner) goto failed;
return ldb_set_opaque(ctx->ldb, "winsdb_handle", h);
failed:
talloc_free(h);
return LDB_ERR_OTHER;
}
static const struct ldb_module_ops wins_ldb_ops = {
.name = "wins_ldb",
.add = wins_ldb_verify,
.modify = wins_ldb_verify,
.init_context = wins_ldb_init
};
/* the init function */
int wins_ldb_module_init(void)
{
return ldb_register_module(&wins_ldb_ops);
}
+257
View File
@@ -0,0 +1,257 @@
/*
Unix SMB/CIFS implementation.
wins client name registration and refresh
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/wins/winsserver.h"
#include "libcli/composite/composite.h"
#include "lib/events/events.h"
#include "librpc/gen_ndr/ndr_nbt.h"
#include "smbd/service_task.h"
static void nbtd_wins_refresh_handler(struct composite_context *c);
/* we send WINS client requests using our primary network interface
*/
static struct nbt_name_socket *wins_socket(struct nbtd_interface *iface)
{
struct nbtd_server *nbtsrv = iface->nbtsrv;
return nbtsrv->interfaces->nbtsock;
}
static void nbtd_wins_refresh(struct event_context *ev, struct timed_event *te,
struct timeval t, void *private_data);
/*
retry a WINS name registration
*/
static void nbtd_wins_register_retry(struct event_context *ev, struct timed_event *te,
struct timeval t, void *private_data)
{
struct nbtd_iface_name *iname = talloc_get_type(private_data, struct nbtd_iface_name);
nbtd_winsclient_register(iname);
}
/*
start a timer to refresh this name
*/
static void nbtd_wins_start_refresh_timer(struct nbtd_iface_name *iname)
{
uint32_t refresh_time;
uint32_t max_refresh_time = lp_parm_int(-1, "nbtd", "max_refresh_time", 7200);
refresh_time = MIN(max_refresh_time, iname->ttl/2);
event_add_timed(iname->iface->nbtsrv->task->event_ctx,
iname,
timeval_add(&iname->registration_time, refresh_time, 0),
nbtd_wins_refresh, iname);
}
/*
called when a wins name refresh has completed
*/
static void nbtd_wins_refresh_handler(struct composite_context *c)
{
NTSTATUS status;
struct nbt_name_refresh_wins io;
struct nbtd_iface_name *iname = talloc_get_type(c->async.private_data,
struct nbtd_iface_name);
TALLOC_CTX *tmp_ctx = talloc_new(iname);
status = nbt_name_refresh_wins_recv(c, tmp_ctx, &io);
if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
/* our WINS server is dead - start registration over
from scratch */
DEBUG(2,("Failed to refresh %s with WINS server %s\n",
nbt_name_string(tmp_ctx, &iname->name), iname->wins_server));
talloc_free(tmp_ctx);
nbtd_winsclient_register(iname);
return;
}
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1,("Name refresh failure with WINS for %s - %s\n",
nbt_name_string(tmp_ctx, &iname->name), nt_errstr(status)));
talloc_free(tmp_ctx);
return;
}
if (io.out.rcode != 0) {
DEBUG(1,("WINS server %s rejected name refresh of %s - %s\n",
io.out.wins_server, nbt_name_string(tmp_ctx, &iname->name),
nt_errstr(nbt_rcode_to_ntstatus(io.out.rcode))));
iname->nb_flags |= NBT_NM_CONFLICT;
talloc_free(tmp_ctx);
return;
}
DEBUG(4,("Refreshed name %s with WINS server %s\n",
nbt_name_string(tmp_ctx, &iname->name), iname->wins_server));
/* success - start a periodic name refresh */
iname->nb_flags |= NBT_NM_ACTIVE;
if (iname->wins_server) {
/*
* talloc_free() would generate a warning,
* so steal it into the tmp context
*/
talloc_steal(tmp_ctx, iname->wins_server);
}
iname->wins_server = talloc_steal(iname, io.out.wins_server);
iname->registration_time = timeval_current();
nbtd_wins_start_refresh_timer(iname);
talloc_free(tmp_ctx);
}
/*
refresh a WINS name registration
*/
static void nbtd_wins_refresh(struct event_context *ev, struct timed_event *te,
struct timeval t, void *private_data)
{
struct nbtd_iface_name *iname = talloc_get_type(private_data, struct nbtd_iface_name);
struct nbtd_interface *iface = iname->iface;
struct nbt_name_refresh_wins io;
struct composite_context *c;
TALLOC_CTX *tmp_ctx = talloc_new(iname);
/* setup a wins name refresh request */
io.in.name = iname->name;
io.in.wins_servers = str_list_make(tmp_ctx, iname->wins_server, NULL);
io.in.addresses = nbtd_address_list(iface, tmp_ctx);
io.in.nb_flags = iname->nb_flags;
io.in.ttl = iname->ttl;
if (!io.in.addresses) {
talloc_free(tmp_ctx);
return;
}
c = nbt_name_refresh_wins_send(wins_socket(iface), &io);
if (c == NULL) {
talloc_free(tmp_ctx);
return;
}
talloc_steal(c, io.in.addresses);
c->async.fn = nbtd_wins_refresh_handler;
c->async.private_data = iname;
talloc_free(tmp_ctx);
}
/*
called when a wins name register has completed
*/
static void nbtd_wins_register_handler(struct composite_context *c)
{
NTSTATUS status;
struct nbt_name_register_wins io;
struct nbtd_iface_name *iname = talloc_get_type(c->async.private_data,
struct nbtd_iface_name);
TALLOC_CTX *tmp_ctx = talloc_new(iname);
status = nbt_name_register_wins_recv(c, tmp_ctx, &io);
if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
/* none of the WINS servers responded - try again
periodically */
int wins_retry_time = lp_parm_int(-1, "nbtd", "wins_retry", 300);
event_add_timed(iname->iface->nbtsrv->task->event_ctx,
iname,
timeval_current_ofs(wins_retry_time, 0),
nbtd_wins_register_retry,
iname);
talloc_free(tmp_ctx);
return;
}
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1,("Name register failure with WINS for %s - %s\n",
nbt_name_string(tmp_ctx, &iname->name), nt_errstr(status)));
talloc_free(tmp_ctx);
return;
}
if (io.out.rcode != 0) {
DEBUG(1,("WINS server %s rejected name register of %s - %s\n",
io.out.wins_server, nbt_name_string(tmp_ctx, &iname->name),
nt_errstr(nbt_rcode_to_ntstatus(io.out.rcode))));
iname->nb_flags |= NBT_NM_CONFLICT;
talloc_free(tmp_ctx);
return;
}
/* success - start a periodic name refresh */
iname->nb_flags |= NBT_NM_ACTIVE;
if (iname->wins_server) {
/*
* talloc_free() would generate a warning,
* so steal it into the tmp context
*/
talloc_steal(tmp_ctx, iname->wins_server);
}
iname->wins_server = talloc_steal(iname, io.out.wins_server);
iname->registration_time = timeval_current();
nbtd_wins_start_refresh_timer(iname);
DEBUG(3,("Registered %s with WINS server %s\n",
nbt_name_string(tmp_ctx, &iname->name), iname->wins_server));
talloc_free(tmp_ctx);
}
/*
register a name with our WINS servers
*/
void nbtd_winsclient_register(struct nbtd_iface_name *iname)
{
struct nbtd_interface *iface = iname->iface;
struct nbt_name_register_wins io;
struct composite_context *c;
/* setup a wins name register request */
io.in.name = iname->name;
io.in.wins_servers = lp_wins_server_list();
io.in.addresses = nbtd_address_list(iface, iname);
io.in.nb_flags = iname->nb_flags;
io.in.ttl = iname->ttl;
if (!io.in.addresses) {
return;
}
c = nbt_name_register_wins_send(wins_socket(iface), &io);
if (c == NULL) {
talloc_free(io.in.addresses);
return;
}
talloc_steal(c, io.in.addresses);
c->async.fn = nbtd_wins_register_handler;
c->async.private_data = iname;
}
File diff suppressed because it is too large Load Diff
+79
View File
@@ -0,0 +1,79 @@
/*
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.
*/
#define WINSDB_FLAG_ALLOC_VERSION (1<<0)
#define WINSDB_FLAG_TAKE_OWNERSHIP (1<<1)
struct winsdb_addr {
const char *address;
const char *wins_owner;
time_t expire_time;
};
/*
each record in the database contains the following information
*/
struct winsdb_record {
struct nbt_name *name;
enum wrepl_name_type type;
enum wrepl_name_state state;
enum wrepl_name_node node;
BOOL is_static;
time_t expire_time;
uint64_t version;
const char *wins_owner;
struct winsdb_addr **addresses;
/* only needed for debugging problems */
const char *registered_by;
};
enum winsdb_handle_caller {
WINSDB_HANDLE_CALLER_ADMIN = 0,
WINSDB_HANDLE_CALLER_NBTD = 1,
WINSDB_HANDLE_CALLER_WREPL = 2
};
struct winsdb_handle {
/* wins server database handle */
struct ldb_context *ldb;
/*
* the type of the caller, as we pass this to the
* 'wins_ldb' ldb module can decide if it needs to verify the
* the records before they're written to disk
*/
enum winsdb_handle_caller caller;
/* local owner address */
const char *local_owner;
};
enum wins_hook_action {
WINS_HOOK_ADD = 0,
WINS_HOOK_MODIFY = 1,
WINS_HOOK_DELETE = 2
};
struct ldb_message;
#include "nbt_server/wins/winsdb_proto.h"
+863
View File
@@ -0,0 +1,863 @@
/*
Unix SMB/CIFS implementation.
core wins server handling
Copyright (C) Andrew Tridgell 2005
Copyright (C) Stefan Metzmacher 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/wins/winsdb.h"
#include "nbt_server/wins/winsserver.h"
#include "librpc/gen_ndr/ndr_nbt.h"
#include "system/time.h"
#include "libcli/composite/composite.h"
#include "smbd/service_task.h"
#include "lib/socket/socket.h"
#include "lib/ldb/include/ldb.h"
/*
work out the ttl we will use given a client requested ttl
*/
uint32_t wins_server_ttl(struct wins_server *winssrv, uint32_t ttl)
{
ttl = MIN(ttl, winssrv->config.max_renew_interval);
ttl = MAX(ttl, winssrv->config.min_renew_interval);
return ttl;
}
static enum wrepl_name_type wrepl_type(uint16_t nb_flags, struct nbt_name *name, BOOL mhomed)
{
/* this copes with the nasty hack that is the type 0x1c name */
if (name->type == NBT_NAME_LOGON) {
return WREPL_TYPE_SGROUP;
}
if (nb_flags & NBT_NM_GROUP) {
return WREPL_TYPE_GROUP;
}
if (mhomed) {
return WREPL_TYPE_MHOMED;
}
return WREPL_TYPE_UNIQUE;
}
/*
register a new name with WINS
*/
static uint8_t wins_register_new(struct nbt_name_socket *nbtsock,
struct nbt_name_packet *packet,
const struct socket_address *src,
enum wrepl_name_type type)
{
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 = wins_server_ttl(winssrv, packet->additional[0].ttl);
uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
struct winsdb_record rec;
enum wrepl_name_node node;
#define WREPL_NODE_NBT_FLAGS(nb_flags) \
((nb_flags & NBT_NM_OWNER_TYPE)>>13)
node = WREPL_NODE_NBT_FLAGS(nb_flags);
rec.name = name;
rec.type = type;
rec.state = WREPL_STATE_ACTIVE;
rec.node = node;
rec.is_static = False;
rec.expire_time = time(NULL) + ttl;
rec.version = 0; /* will be allocated later */
rec.wins_owner = NULL; /* will be set later */
rec.registered_by = src->addr;
rec.addresses = winsdb_addr_list_make(packet);
if (rec.addresses == NULL) return NBT_RCODE_SVR;
rec.addresses = winsdb_addr_list_add(winssrv->wins_db,
&rec, rec.addresses,
address,
winssrv->wins_db->local_owner,
rec.expire_time,
True);
if (rec.addresses == NULL) return NBT_RCODE_SVR;
DEBUG(4,("WINS: accepted registration of %s with address %s\n",
nbt_name_string(packet, name), rec.addresses[0]->address));
return winsdb_add(winssrv->wins_db, &rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
}
/*
update the ttl on an existing record
*/
static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock,
struct nbt_name_packet *packet,
struct winsdb_record *rec,
struct winsdb_addr *winsdb_addr,
const struct socket_address *src)
{
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
struct nbtd_interface);
struct wins_server *winssrv = iface->nbtsrv->winssrv;
uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
uint32_t modify_flags = 0;
rec->expire_time = time(NULL) + ttl;
rec->registered_by = src->addr;
if (winsdb_addr) {
rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
rec, rec->addresses,
winsdb_addr->address,
winssrv->wins_db->local_owner,
rec->expire_time,
True);
if (rec->addresses == NULL) return NBT_RCODE_SVR;
}
if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) {
modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
}
DEBUG(5,("WINS: refreshed registration of %s at %s\n",
nbt_name_string(packet, rec->name), address));
return winsdb_modify(winssrv->wins_db, rec, modify_flags);
}
/*
do a sgroup merge
*/
static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
struct nbt_name_packet *packet,
struct winsdb_record *rec,
const char *address,
const struct socket_address *src)
{
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
struct nbtd_interface);
struct wins_server *winssrv = iface->nbtsrv->winssrv;
uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
rec->expire_time = time(NULL) + ttl;
rec->registered_by = src->addr;
rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
rec, rec->addresses,
address,
winssrv->wins_db->local_owner,
rec->expire_time,
True);
if (rec->addresses == NULL) return NBT_RCODE_SVR;
DEBUG(5,("WINS: sgroup merge of %s at %s\n",
nbt_name_string(packet, rec->name), address));
return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
}
struct wack_state {
struct wins_server *winssrv;
struct nbt_name_socket *nbtsock;
struct nbt_name_packet *request_packet;
struct winsdb_record *rec;
struct socket_address *src;
const char *reg_address;
enum wrepl_name_type new_type;
struct wins_challenge_io io;
NTSTATUS status;
};
/*
deny a registration request
*/
static void wins_wack_deny(struct wack_state *s)
{
nbtd_name_registration_reply(s->nbtsock, s->request_packet,
s->src, NBT_RCODE_ACT);
DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
nbt_name_string(s, s->rec->name), s->src->addr, s->src->port));
talloc_free(s);
}
/*
allow a registration request
*/
static void wins_wack_allow(struct wack_state *s)
{
NTSTATUS status;
uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
struct winsdb_record *rec = s->rec, *rec2;
uint32_t i,j;
status = winsdb_lookup(s->winssrv->wins_db, rec->name, s, &rec2);
if (!NT_STATUS_IS_OK(status) ||
rec2->version != rec->version ||
strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
DEBUG(1,("WINS: record %s changed during WACK - failing registration\n",
nbt_name_string(s, rec->name)));
wins_wack_deny(s);
return;
}
/*
* if the old name owner doesn't hold the name anymore
* handle the request as new registration for the new name owner
*/
if (!NT_STATUS_IS_OK(s->status)) {
uint8_t rcode;
winsdb_delete(s->winssrv->wins_db, rec);
rcode = wins_register_new(s->nbtsock, s->request_packet, s->src, s->new_type);
if (rcode != NBT_RCODE_OK) {
DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
nbt_name_string(s, rec->name)));
wins_wack_deny(s);
return;
}
goto done;
}
rec->expire_time = time(NULL) + ttl;
rec->registered_by = s->src->addr;
/*
* now remove all addresses that're the client doesn't hold anymore
* and update the time stamp and owner for the ownes that are still there
*/
for (i=0; rec->addresses[i]; i++) {
BOOL found = False;
for (j=0; j < s->io.out.num_addresses; j++) {
if (strcmp(rec->addresses[i]->address, s->io.out.addresses[j]) != 0) continue;
found = True;
break;
}
if (found) {
rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
rec, rec->addresses,
s->reg_address,
s->winssrv->wins_db->local_owner,
rec->expire_time,
True);
if (rec->addresses == NULL) goto failed;
continue;
}
winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
}
rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
rec, rec->addresses,
s->reg_address,
s->winssrv->wins_db->local_owner,
rec->expire_time,
True);
if (rec->addresses == NULL) goto failed;
/* if we have more than one address, this becomes implicit a MHOMED record */
if (winsdb_addr_list_length(rec->addresses) > 1) {
rec->type = WREPL_TYPE_MHOMED;
}
winsdb_modify(s->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
DEBUG(4,("WINS: accepted registration of %s with address %s\n",
nbt_name_string(s, rec->name), s->reg_address));
done:
nbtd_name_registration_reply(s->nbtsock, s->request_packet,
s->src, NBT_RCODE_OK);
failed:
talloc_free(s);
}
/*
called when a name query to a current owner completes
*/
static void wack_wins_challenge_handler(struct composite_context *c_req)
{
struct wack_state *s = talloc_get_type(c_req->async.private_data,
struct wack_state);
BOOL found;
uint32_t i;
s->status = wins_challenge_recv(c_req, s, &s->io);
/*
* if the owner denies it holds the name, then allow
* the registration
*/
if (!NT_STATUS_IS_OK(s->status)) {
wins_wack_allow(s);
return;
}
if (s->new_type == WREPL_TYPE_GROUP || s->new_type == WREPL_TYPE_SGROUP) {
DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
nbt_name_string(s, s->rec->name), s->new_type, s->rec->type));
wins_wack_deny(s);
return;
}
/*
* if the owner still wants the name and doesn't reply
* with the address trying to be registered, then deny
* the registration
*/
found = False;
for (i=0; i < s->io.out.num_addresses; i++) {
if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
found = True;
break;
}
if (!found) {
wins_wack_deny(s);
return;
}
wins_wack_allow(s);
return;
}
/*
a client has asked to register a unique name that someone else owns. We
need to ask each of the current owners if they still want it. If they do
then reject the registration, otherwise allow it
*/
static void wins_register_wack(struct nbt_name_socket *nbtsock,
struct nbt_name_packet *packet,
struct winsdb_record *rec,
struct socket_address *src,
enum wrepl_name_type new_type)
{
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
struct nbtd_interface);
struct wins_server *winssrv = iface->nbtsrv->winssrv;
struct wack_state *s;
struct composite_context *c_req;
uint32_t ttl;
s = talloc_zero(nbtsock, struct wack_state);
if (s == NULL) goto failed;
/* package up the state variables for this wack request */
s->winssrv = winssrv;
s->nbtsock = nbtsock;
s->request_packet = talloc_steal(s, packet);
s->rec = talloc_steal(s, rec);
s->reg_address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
s->new_type = new_type;
s->src = src;
if (talloc_reference(s, src) == NULL) goto failed;
s->io.in.nbtd_server = iface->nbtsrv;
s->io.in.event_ctx = iface->nbtsrv->task->event_ctx;
s->io.in.name = rec->name;
s->io.in.num_addresses = winsdb_addr_list_length(rec->addresses);
s->io.in.addresses = winsdb_addr_string_list(s, rec->addresses);
if (s->io.in.addresses == NULL) goto failed;
/*
* send a WACK to the client, specifying the maximum time it could
* take to check with the owner, plus some slack
*/
ttl = 5 + 4 * winsdb_addr_list_length(rec->addresses);
nbtd_wack_reply(nbtsock, packet, src, ttl);
/*
* send the challenge to the old addresses
*/
c_req = wins_challenge_send(s, &s->io);
if (c_req == NULL) goto failed;
c_req->async.fn = wack_wins_challenge_handler;
c_req->async.private_data = s;
return;
failed:
talloc_free(s);
nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR);
}
/*
register a name
*/
static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
struct nbt_name_packet *packet,
struct socket_address *src)
{
NTSTATUS status;
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 = NBT_RCODE_OK;
uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
BOOL mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
struct winsdb_addr *winsdb_addr = NULL;
/*
* as a special case, the local master browser name is always accepted
* for registration, but never stored, but w2k3 stores it if it's registered
* as a group name, (but a query for the 0x1D name still returns not found!)
*/
if (name->type == NBT_NAME_MASTER && !(nb_flags & NBT_NM_GROUP)) {
rcode = NBT_RCODE_OK;
goto done;
}
/* w2k3 refuses 0x1B names with marked as group */
if (name->type == NBT_NAME_PDC && (nb_flags & NBT_NM_GROUP)) {
rcode = NBT_RCODE_RFS;
goto done;
}
/* w2k3 refuses 0x1C names with out marked as group */
if (name->type == NBT_NAME_LOGON && !(nb_flags & NBT_NM_GROUP)) {
rcode = NBT_RCODE_RFS;
goto done;
}
/* w2k3 refuses 0x1E names with out marked as group */
if (name->type == NBT_NAME_BROWSER && !(nb_flags & NBT_NM_GROUP)) {
rcode = NBT_RCODE_RFS;
goto done;
}
status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
rcode = wins_register_new(nbtsock, packet, src, new_type);
goto done;
} else if (!NT_STATUS_IS_OK(status)) {
rcode = NBT_RCODE_SVR;
goto done;
} else if (rec->is_static) {
if (rec->type == WREPL_TYPE_GROUP || rec->type == WREPL_TYPE_SGROUP) {
rcode = NBT_RCODE_OK;
goto done;
}
rcode = NBT_RCODE_ACT;
goto done;
}
if (rec->type == WREPL_TYPE_GROUP) {
if (new_type != WREPL_TYPE_GROUP) {
DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
" while a normal group is already there\n",
nbt_name_string(packet, name), new_type));
rcode = NBT_RCODE_ACT;
goto done;
}
if (rec->state == WREPL_STATE_ACTIVE) {
/* TODO: is this correct? */
rcode = wins_update_ttl(nbtsock, packet, rec, NULL, src);
goto done;
}
/* TODO: is this correct? */
winsdb_delete(winssrv->wins_db, rec);
rcode = wins_register_new(nbtsock, packet, src, new_type);
goto done;
}
if (rec->state != WREPL_STATE_ACTIVE) {
winsdb_delete(winssrv->wins_db, rec);
rcode = wins_register_new(nbtsock, packet, src, new_type);
goto done;
}
switch (rec->type) {
case WREPL_TYPE_UNIQUE:
case WREPL_TYPE_MHOMED:
/*
* if its an active unique name, and the registration is for a group, then
* see if the unique name owner still wants the name
* TODO: is this correct?
*/
if (new_type == WREPL_TYPE_GROUP || new_type == WREPL_TYPE_GROUP) {
wins_register_wack(nbtsock, packet, rec, src, new_type);
return;
}
/*
* if the registration is for an address that is currently active, then
* just update the expiry time of the record and the address
*/
winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
if (winsdb_addr) {
rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
goto done;
}
/*
* we have to do a WACK to see if the current owner is willing
* to give up its claim
*/
wins_register_wack(nbtsock, packet, rec, src, new_type);
return;
case WREPL_TYPE_GROUP:
/* this should not be reached as normal groups are handled above */
DEBUG(0,("BUG at %s\n",__location__));
rcode = NBT_RCODE_ACT;
goto done;
case WREPL_TYPE_SGROUP:
/* if the new record isn't also a special group, refuse the registration */
if (new_type != WREPL_TYPE_SGROUP) {
DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
" while a special group is already there\n",
nbt_name_string(packet, name), new_type));
rcode = NBT_RCODE_ACT;
goto done;
}
/*
* if the registration is for an address that is currently active, then
* just update the expiry time of the record and the address
*/
winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
if (winsdb_addr) {
rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
goto done;
}
rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
goto done;
}
done:
nbtd_name_registration_reply(nbtsock, packet, src, rcode);
}
/*
query a name
*/
static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock,
struct nbt_name_packet *packet,
struct socket_address *src)
{
NTSTATUS status;
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;
struct winsdb_record *rec_1b = NULL;
const char **addresses;
const char **addresses_1b = NULL;
uint16_t nb_flags = 0;
if (name->type == NBT_NAME_MASTER) {
goto notfound;
}
/*
* w2k3 returns the first address of the 0x1B record as first address
* to a 0x1C query
*/
if (name->type == NBT_NAME_LOGON) {
struct nbt_name name_1b;
name_1b = *name;
name_1b.type = NBT_NAME_PDC;
status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
if (NT_STATUS_IS_OK(status)) {
addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
}
}
status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
if (!NT_STATUS_IS_OK(status)) {
if (!lp_wins_dns_proxy()) {
goto notfound;
}
if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
goto notfound;
}
nbtd_wins_dns_proxy_query(nbtsock, packet, src);
return;
}
/*
* for group's we always reply with
* 255.255.255.255 as address, even if
* the record is released or tombstoned
*/
if (rec->type == WREPL_TYPE_GROUP) {
addresses = str_list_add(NULL, "255.255.255.255");
talloc_steal(packet, addresses);
if (!addresses) {
goto notfound;
}
nb_flags |= NBT_NM_GROUP;
goto found;
}
if (rec->state != WREPL_STATE_ACTIVE) {
goto notfound;
}
addresses = winsdb_addr_string_list(packet, rec->addresses);
if (!addresses) {
goto notfound;
}
/*
* if addresses_1b isn't NULL, we have a 0x1C query and need to return the
* first 0x1B address as first address
*/
if (addresses_1b && addresses_1b[0]) {
const char **addresses_1c = addresses;
uint32_t i;
uint32_t num_addrs;
addresses = str_list_add(NULL, addresses_1b[0]);
if (!addresses) {
goto notfound;
}
talloc_steal(packet, addresses);
num_addrs = 1;
for (i=0; addresses_1c[i]; i++) {
if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
/*
* stop when we already have 25 addresses
*/
if (num_addrs >= 25) break;
num_addrs++;
addresses = str_list_add(addresses, addresses_1c[i]);
if (!addresses) {
goto notfound;
}
}
}
if (rec->type == WREPL_TYPE_SGROUP) {
nb_flags |= NBT_NM_GROUP;
} else {
nb_flags |= (rec->node <<13);
}
found:
nbtd_name_query_reply(nbtsock, packet, src, name,
0, nb_flags, addresses);
return;
notfound:
nbtd_negative_name_query_reply(nbtsock, packet, src);
}
/*
release a name
*/
static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
struct nbt_name_packet *packet,
struct socket_address *src)
{
NTSTATUS status;
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;
uint32_t modify_flags = 0;
uint8_t ret;
if (name->type == NBT_NAME_MASTER) {
goto done;
}
status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
if (rec->is_static) {
if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
goto done;
}
nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
return;
}
if (rec->state != WREPL_STATE_ACTIVE) {
goto done;
}
/*
* TODO: do we need to check if
* src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
* here?
*/
/*
* we only allow releases from an owner - other releases are
* silently ignored
*/
if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
int i;
DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
DEBUGADD(4, ("Registered Addresses: \n"));
for (i=0; rec->addresses && rec->addresses[i]; i++) {
DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
}
goto done;
}
DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
switch (rec->type) {
case WREPL_TYPE_UNIQUE:
rec->state = WREPL_STATE_RELEASED;
break;
case WREPL_TYPE_GROUP:
rec->state = WREPL_STATE_RELEASED;
break;
case WREPL_TYPE_SGROUP:
winsdb_addr_list_remove(rec->addresses, src->addr);
/* TODO: do we need to take the ownership here? */
if (winsdb_addr_list_length(rec->addresses) == 0) {
rec->state = WREPL_STATE_RELEASED;
}
break;
case WREPL_TYPE_MHOMED:
winsdb_addr_list_remove(rec->addresses, src->addr);
/* TODO: do we need to take the ownership here? */
if (winsdb_addr_list_length(rec->addresses) == 0) {
rec->state = WREPL_STATE_RELEASED;
}
break;
}
if (rec->state == WREPL_STATE_RELEASED) {
/*
* if we're not the owner, we need to take the owner ship
* and make the record tombstone, but expire after
* tombstone_interval + tombstone_timeout and not only after tombstone_timeout
* like for normal tombstone records.
* This is to replicate the record directly to the original owner,
* where the record is still active
*/
if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
} else {
rec->state = WREPL_STATE_TOMBSTONE;
rec->expire_time= time(NULL) +
winssrv->config.tombstone_interval +
winssrv->config.tombstone_timeout;
modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
}
}
ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
if (ret != NBT_RCODE_OK) {
DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
nbt_name_string(rec, rec->name), src->addr, ret));
}
done:
/* we match w2k3 by always giving a positive reply to name releases. */
nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
}
/*
answer a name query
*/
void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
struct nbt_name_packet *packet,
struct socket_address *src)
{
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;
}
switch (packet->operation & NBT_OPCODE) {
case NBT_OPCODE_QUERY:
nbtd_winsserver_query(nbtsock, packet, src);
break;
case NBT_OPCODE_REGISTER:
case NBT_OPCODE_REFRESH:
case NBT_OPCODE_REFRESH2:
case NBT_OPCODE_MULTI_HOME_REG:
nbtd_winsserver_register(nbtsock, packet, src);
break;
case NBT_OPCODE_RELEASE:
nbtd_winsserver_release(nbtsock, packet, src);
break;
}
}
/*
startup the WINS server, if configured
*/
NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
{
uint32_t tmp;
if (!lp_wins_support()) {
nbtsrv->winssrv = NULL;
return NT_STATUS_OK;
}
nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl();
nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl();
tmp = lp_parm_int(-1,"wreplsrv","tombstone_interval", 6*24*60*60);
nbtsrv->winssrv->config.tombstone_interval = tmp;
tmp = lp_parm_int(-1,"wreplsrv","tombstone_timeout", 1*24*60*60);
nbtsrv->winssrv->config.tombstone_timeout = tmp;
nbtsrv->winssrv->wins_db = winsdb_connect(nbtsrv->winssrv, WINSDB_HANDLE_CALLER_NBTD);
if (!nbtsrv->winssrv->wins_db) {
return NT_STATUS_INTERNAL_DB_ERROR;
}
irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");
return NT_STATUS_OK;
}
+66
View File
@@ -0,0 +1,66 @@
/*
Unix SMB/CIFS implementation.
wins server WACK processing
Copyright (C) Stefan Metzmacher 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.
*/
struct wins_server {
/* wins server database handle */
struct winsdb_handle *wins_db;
/* some configuration */
struct {
/*
* the interval (in secs) till an active record will be marked as RELEASED
*/
uint32_t min_renew_interval;
uint32_t max_renew_interval;
/*
* the interval (in secs) a record remains in RELEASED state,
* before it will be marked as TOMBSTONE
* (also known as extinction interval)
*/
uint32_t tombstone_interval;
/*
* the interval (in secs) a record remains in TOMBSTONE state,
* before it will be removed from the database.
* See also 'tombstone_extra_timeout'.
* (also known as extinction timeout)
*/
uint32_t tombstone_timeout;
} config;
};
struct wins_challenge_io {
struct {
struct nbtd_server *nbtd_server;
struct event_context *event_ctx;
struct nbt_name *name;
uint32_t num_addresses;
const char **addresses;
} in;
struct {
uint32_t num_addresses;
const char **addresses;
} out;
};
#include "nbt_server/wins/winsserver_proto.h"
+381
View File
@@ -0,0 +1,381 @@
/*
Unix SMB/CIFS implementation.
"secure" wins server WACK processing
Copyright (C) Andrew Tridgell 2005
Copyright (C) Stefan Metzmacher 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/wins/winsdb.h"
#include "nbt_server/wins/winsserver.h"
#include "system/time.h"
#include "libcli/composite/composite.h"
struct wins_challenge_state {
struct wins_challenge_io *io;
uint32_t current_address;
struct nbt_name_query query;
};
static void wins_challenge_handler(struct nbt_name_request *req)
{
struct composite_context *ctx = talloc_get_type(req->async.private, struct composite_context);
struct wins_challenge_state *state = talloc_get_type(ctx->private_data, struct wins_challenge_state);
ctx->status = nbt_name_query_recv(req, state, &state->query);
/* if we timed out then try the next owner address, if any */
if (NT_STATUS_EQUAL(ctx->status, NT_STATUS_IO_TIMEOUT)) {
state->current_address++;
if (state->current_address < state->io->in.num_addresses) {
struct nbtd_interface *iface;
state->query.in.dest_addr = state->io->in.addresses[state->current_address];
iface = nbtd_find_request_iface(state->io->in.nbtd_server, state->query.in.dest_addr, True);
if (!iface) {
composite_error(ctx, NT_STATUS_INTERNAL_ERROR);
return;
}
ZERO_STRUCT(state->query.out);
req = nbt_name_query_send(iface->nbtsock, &state->query);
composite_continue_nbt(ctx, req, wins_challenge_handler, ctx);
return;
}
}
composite_done(ctx);
}
NTSTATUS wins_challenge_recv(struct composite_context *ctx, TALLOC_CTX *mem_ctx, struct wins_challenge_io *io)
{
NTSTATUS status = ctx->status;
struct wins_challenge_state *state = talloc_get_type(ctx->private_data, struct wins_challenge_state);
if (NT_STATUS_IS_OK(status)) {
io->out.num_addresses = state->query.out.num_addrs;
io->out.addresses = state->query.out.reply_addrs;
talloc_steal(mem_ctx, io->out.addresses);
} else {
ZERO_STRUCT(io->out);
}
talloc_free(ctx);
return status;
}
struct composite_context *wins_challenge_send(TALLOC_CTX *mem_ctx, struct wins_challenge_io *io)
{
struct composite_context *result;
struct wins_challenge_state *state;
struct nbt_name_request *req;
struct nbtd_interface *iface;
result = talloc_zero(mem_ctx, struct composite_context);
if (result == NULL) return NULL;
result->state = COMPOSITE_STATE_IN_PROGRESS;
result->event_ctx = talloc_reference(result, io->in.event_ctx);
state = talloc_zero(result, struct wins_challenge_state);
if (state == NULL) goto failed;
result->private_data = state;
/* package up the state variables for this wack request */
state->io = io;
state->current_address = 0;
/* setup a name query to the first address */
state->query.in.name = *state->io->in.name;
state->query.in.dest_addr = state->io->in.addresses[state->current_address];
state->query.in.broadcast = False;
state->query.in.wins_lookup = True;
state->query.in.timeout = 1;
state->query.in.retries = 2;
ZERO_STRUCT(state->query.out);
iface = nbtd_find_request_iface(state->io->in.nbtd_server, state->query.in.dest_addr, True);
if (!iface) {
goto failed;
}
req = nbt_name_query_send(iface->nbtsock, &state->query);
if (req == NULL) goto failed;
req->async.fn = wins_challenge_handler;
req->async.private = result;
return result;
failed:
talloc_free(result);
return NULL;
}
struct wins_release_demand_io {
struct {
struct nbtd_server *nbtd_server;
struct event_context *event_ctx;
struct nbt_name *name;
uint16_t nb_flags;
uint32_t num_addresses;
const char **addresses;
} in;
};
struct wins_release_demand_state {
struct wins_release_demand_io *io;
uint32_t current_address;
uint32_t addresses_left;
struct nbt_name_release release;
};
static void wins_release_demand_handler(struct nbt_name_request *req)
{
struct composite_context *ctx = talloc_get_type(req->async.private, struct composite_context);
struct wins_release_demand_state *state = talloc_get_type(ctx->private_data, struct wins_release_demand_state);
ctx->status = nbt_name_release_recv(req, state, &state->release);
/* if we timed out then try the next owner address, if any */
if (NT_STATUS_EQUAL(ctx->status, NT_STATUS_IO_TIMEOUT)) {
state->current_address++;
state->addresses_left--;
if (state->current_address < state->io->in.num_addresses) {
struct nbtd_interface *iface;
state->release.in.dest_addr = state->io->in.addresses[state->current_address];
state->release.in.address = state->release.in.dest_addr;
state->release.in.timeout = (state->addresses_left > 1 ? 2 : 1);
state->release.in.retries = (state->addresses_left > 1 ? 0 : 2);
iface = nbtd_find_request_iface(state->io->in.nbtd_server, state->release.in.dest_addr, True);
if (!iface) {
composite_error(ctx, NT_STATUS_INTERNAL_ERROR);
return;
}
ZERO_STRUCT(state->release.out);
req = nbt_name_release_send(iface->nbtsock, &state->release);
composite_continue_nbt(ctx, req, wins_release_demand_handler, ctx);
return;
}
}
composite_done(ctx);
}
static NTSTATUS wins_release_demand_recv(struct composite_context *ctx,
TALLOC_CTX *mem_ctx,
struct wins_release_demand_io *io)
{
NTSTATUS status = ctx->status;
talloc_free(ctx);
return status;
}
static struct composite_context *wins_release_demand_send(TALLOC_CTX *mem_ctx, struct wins_release_demand_io *io)
{
struct composite_context *result;
struct wins_release_demand_state *state;
struct nbt_name_request *req;
struct nbtd_interface *iface;
result = talloc_zero(mem_ctx, struct composite_context);
if (result == NULL) return NULL;
result->state = COMPOSITE_STATE_IN_PROGRESS;
result->event_ctx = talloc_reference(result, io->in.event_ctx);
state = talloc_zero(result, struct wins_release_demand_state);
if (state == NULL) goto failed;
result->private_data = state;
/* package up the state variables for this wack request */
state->io = io;
state->current_address = 0;
state->addresses_left = state->io->in.num_addresses;
/*
* setup a name query to the first address
* - if we have more than one address try the first
* with 2 secs timeout and no retry
* - otherwise use 1 sec timeout (w2k3 uses 0.5 sec here)
* with 2 retries
*/
state->release.in.name = *state->io->in.name;
state->release.in.dest_addr = state->io->in.addresses[state->current_address];
state->release.in.address = state->release.in.dest_addr;
state->release.in.broadcast = False;
state->release.in.timeout = (state->addresses_left > 1 ? 2 : 1);
state->release.in.retries = (state->addresses_left > 1 ? 0 : 2);
ZERO_STRUCT(state->release.out);
iface = nbtd_find_request_iface(state->io->in.nbtd_server, state->release.in.dest_addr, True);
if (!iface) {
goto failed;
}
req = nbt_name_release_send(iface->nbtsock, &state->release);
if (req == NULL) goto failed;
req->async.fn = wins_release_demand_handler;
req->async.private = result;
return result;
failed:
talloc_free(result);
return NULL;
}
/*
wrepl_server needs to be able to do a name query request, but some windows
servers always send the reply to port 137, regardless of the request
port. To cope with this we use a irpc request to the NBT server
which has port 137 open, and thus can receive the replies
*/
struct proxy_wins_challenge_state {
struct irpc_message *msg;
struct nbtd_proxy_wins_challenge *req;
struct wins_challenge_io io;
struct composite_context *c_req;
};
static void proxy_wins_challenge_handler(struct composite_context *c_req)
{
NTSTATUS status;
uint32_t i;
struct proxy_wins_challenge_state *s = talloc_get_type(c_req->async.private_data,
struct proxy_wins_challenge_state);
status = wins_challenge_recv(s->c_req, s, &s->io);
if (!NT_STATUS_IS_OK(status)) {
ZERO_STRUCT(s->req->out);
irpc_send_reply(s->msg, status);
return;
}
s->req->out.num_addrs = s->io.out.num_addresses;
/* TODO: fix pidl to handle inline ipv4address arrays */
s->req->out.addrs = talloc_array(s->msg, struct nbtd_proxy_wins_addr,
s->io.out.num_addresses);
if (!s->req->out.addrs) {
ZERO_STRUCT(s->req->out);
irpc_send_reply(s->msg, NT_STATUS_NO_MEMORY);
return;
}
for (i=0; i < s->io.out.num_addresses; i++) {
s->req->out.addrs[i].addr = talloc_steal(s->req->out.addrs, s->io.out.addresses[i]);
}
irpc_send_reply(s->msg, status);
}
NTSTATUS nbtd_proxy_wins_challenge(struct irpc_message *msg,
struct nbtd_proxy_wins_challenge *req)
{
struct nbtd_server *nbtd_server =
talloc_get_type(msg->private, struct nbtd_server);
struct proxy_wins_challenge_state *s;
uint32_t i;
s = talloc(msg, struct proxy_wins_challenge_state);
NT_STATUS_HAVE_NO_MEMORY(s);
s->msg = msg;
s->req = req;
s->io.in.nbtd_server = nbtd_server;
s->io.in.event_ctx = msg->ev;
s->io.in.name = &req->in.name;
s->io.in.num_addresses = req->in.num_addrs;
s->io.in.addresses = talloc_array(s, const char *, req->in.num_addrs);
NT_STATUS_HAVE_NO_MEMORY(s->io.in.addresses);
/* TODO: fix pidl to handle inline ipv4address arrays */
for (i=0; i < req->in.num_addrs; i++) {
s->io.in.addresses[i] = talloc_steal(s->io.in.addresses, req->in.addrs[i].addr);
}
s->c_req = wins_challenge_send(s, &s->io);
NT_STATUS_HAVE_NO_MEMORY(s->c_req);
s->c_req->async.fn = proxy_wins_challenge_handler;
s->c_req->async.private_data = s;
msg->defer_reply = True;
return NT_STATUS_OK;
}
/*
wrepl_server needs to be able to do a name release demands, but some windows
servers always send the reply to port 137, regardless of the request
port. To cope with this we use a irpc request to the NBT server
which has port 137 open, and thus can receive the replies
*/
struct proxy_wins_release_demand_state {
struct irpc_message *msg;
struct nbtd_proxy_wins_release_demand *req;
struct wins_release_demand_io io;
struct composite_context *c_req;
};
static void proxy_wins_release_demand_handler(struct composite_context *c_req)
{
NTSTATUS status;
struct proxy_wins_release_demand_state *s = talloc_get_type(c_req->async.private_data,
struct proxy_wins_release_demand_state);
status = wins_release_demand_recv(s->c_req, s, &s->io);
irpc_send_reply(s->msg, status);
}
NTSTATUS nbtd_proxy_wins_release_demand(struct irpc_message *msg,
struct nbtd_proxy_wins_release_demand *req)
{
struct nbtd_server *nbtd_server =
talloc_get_type(msg->private, struct nbtd_server);
struct proxy_wins_release_demand_state *s;
uint32_t i;
s = talloc(msg, struct proxy_wins_release_demand_state);
NT_STATUS_HAVE_NO_MEMORY(s);
s->msg = msg;
s->req = req;
s->io.in.nbtd_server = nbtd_server;
s->io.in.event_ctx = msg->ev;
s->io.in.name = &req->in.name;
s->io.in.num_addresses = req->in.num_addrs;
s->io.in.addresses = talloc_array(s, const char *, req->in.num_addrs);
NT_STATUS_HAVE_NO_MEMORY(s->io.in.addresses);
/* TODO: fix pidl to handle inline ipv4address arrays */
for (i=0; i < req->in.num_addrs; i++) {
s->io.in.addresses[i] = talloc_steal(s->io.in.addresses, req->in.addrs[i].addr);
}
s->c_req = wins_release_demand_send(s, &s->io);
NT_STATUS_HAVE_NO_MEMORY(s->c_req);
s->c_req->async.fn = proxy_wins_release_demand_handler;
s->c_req->async.private_data = s;
msg->defer_reply = True;
return NT_STATUS_OK;
}