wmi-1.3.16 from opsview.com
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
# NBTD server subsystem
|
||||
|
||||
#######################
|
||||
# Start SUBSYSTEM WINSDB
|
||||
[SUBSYSTEM::WINSDB]
|
||||
OBJ_FILES = \
|
||||
wins/winsdb.o \
|
||||
wins/wins_hook.o
|
||||
PRIVATE_PROTO_HEADER = wins/winsdb_proto.h
|
||||
PUBLIC_DEPENDENCIES = \
|
||||
ldb
|
||||
# End SUBSYSTEM WINSDB
|
||||
#######################
|
||||
|
||||
#######################
|
||||
# Start MODULE ldb_wins_ldb
|
||||
[MODULE::ldb_wins_ldb]
|
||||
SUBSYSTEM = ldb
|
||||
INIT_FUNCTION = wins_ldb_module_init
|
||||
OBJ_FILES = \
|
||||
wins/wins_ldb.o
|
||||
PUBLIC_DEPENDENCIES = \
|
||||
LIBNETIF
|
||||
# End MODULE ldb_wins_ldb
|
||||
#######################
|
||||
|
||||
#######################
|
||||
# Start SUBSYSTEM NBTD_WINS
|
||||
[SUBSYSTEM::NBTD_WINS]
|
||||
OBJ_FILES = \
|
||||
wins/winsserver.o \
|
||||
wins/winsclient.o \
|
||||
wins/winswack.o \
|
||||
wins/wins_dns_proxy.o
|
||||
PRIVATE_PROTO_HEADER = wins/winsserver_proto.h
|
||||
PUBLIC_DEPENDENCIES = \
|
||||
LIBCLI_NBT WINSDB
|
||||
# End SUBSYSTEM NBTD_WINS
|
||||
#######################
|
||||
|
||||
#######################
|
||||
# Start SUBSYSTEM NBTD_DGRAM
|
||||
[SUBSYSTEM::NBTD_DGRAM]
|
||||
PRIVATE_PROTO_HEADER = dgram/proto.h
|
||||
OBJ_FILES = \
|
||||
dgram/request.o \
|
||||
dgram/netlogon.o \
|
||||
dgram/ntlogon.o \
|
||||
dgram/browse.o
|
||||
PUBLIC_DEPENDENCIES = \
|
||||
LIBCLI_DGRAM
|
||||
# End SUBSYSTEM NBTD_DGRAM
|
||||
#######################
|
||||
|
||||
#######################
|
||||
# Start SUBSYSTEM NBTD
|
||||
[MODULE::NBTD]
|
||||
INIT_FUNCTION = server_service_nbtd_init
|
||||
SUBSYSTEM = service
|
||||
OBJ_FILES = \
|
||||
nbt_server.o \
|
||||
interfaces.o \
|
||||
register.o \
|
||||
query.o \
|
||||
nodestatus.o \
|
||||
defense.o \
|
||||
packet.o \
|
||||
irpc.o
|
||||
PRIVATE_PROTO_HEADER = nbt_server_proto.h
|
||||
PUBLIC_DEPENDENCIES = \
|
||||
LIBCLI_NBT NBTD_WINS NBTD_DGRAM process_model
|
||||
# End SUBSYSTEM NBTD
|
||||
#######################
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
defend our names against name registration requests
|
||||
|
||||
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/util/dlinklist.h"
|
||||
#include "system/network.h"
|
||||
#include "nbt_server/nbt_server.h"
|
||||
#include "nbt_server/wins/winsserver.h"
|
||||
#include "librpc/gen_ndr/ndr_nbt.h"
|
||||
#include "lib/socket/socket.h"
|
||||
|
||||
|
||||
/*
|
||||
defend our registered names against registration or name refresh
|
||||
requests
|
||||
*/
|
||||
void nbtd_request_defense(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *packet,
|
||||
struct socket_address *src)
|
||||
{
|
||||
struct nbtd_iface_name *iname;
|
||||
struct nbt_name *name;
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
|
||||
/*
|
||||
* if the packet comes from one of our interfaces
|
||||
* it must be our winsclient trying to reach the winsserver
|
||||
*/
|
||||
if (nbtd_self_packet(nbtsock, packet, src)) {
|
||||
nbtd_winsserver_request(nbtsock, packet, src);
|
||||
return;
|
||||
}
|
||||
|
||||
NBTD_ASSERT_PACKET(packet, src, packet->qdcount == 1);
|
||||
NBTD_ASSERT_PACKET(packet, src, packet->arcount == 1);
|
||||
NBTD_ASSERT_PACKET(packet, src,
|
||||
packet->questions[0].question_type == NBT_QTYPE_NETBIOS);
|
||||
NBTD_ASSERT_PACKET(packet, src,
|
||||
packet->questions[0].question_class == NBT_QCLASS_IP);
|
||||
NBTD_ASSERT_PACKET(packet, src,
|
||||
packet->additional[0].rr_type == NBT_QTYPE_NETBIOS);
|
||||
NBTD_ASSERT_PACKET(packet, src,
|
||||
packet->additional[0].rr_class == NBT_QCLASS_IP);
|
||||
NBTD_ASSERT_PACKET(packet, src,
|
||||
packet->additional[0].rdata.netbios.length == 6);
|
||||
|
||||
/* see if we have the requested name on this interface */
|
||||
name = &packet->questions[0].name;
|
||||
|
||||
iname = nbtd_find_iname(iface, name, NBT_NM_ACTIVE);
|
||||
if (iname != NULL &&
|
||||
!(name->type == NBT_NAME_LOGON || iname->nb_flags & NBT_NM_GROUP)) {
|
||||
DEBUG(2,("Defending name %s on %s against %s\n",
|
||||
nbt_name_string(packet, name),
|
||||
iface->bcast_address, src->addr));
|
||||
nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_ACT);
|
||||
} else {
|
||||
nbtd_winsserver_request(nbtsock, packet, src);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
NBT datagram browse server
|
||||
|
||||
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 "lib/socket/socket.h"
|
||||
#include "librpc/gen_ndr/ndr_nbt.h"
|
||||
|
||||
static const char *nbt_browse_opcode_string(enum nbt_browse_opcode r)
|
||||
{
|
||||
const char *val = NULL;
|
||||
|
||||
switch (r) {
|
||||
case HostAnnouncement: val = "HostAnnouncement"; break;
|
||||
case AnnouncementRequest: val = "AnnouncementRequest"; break;
|
||||
case Election: val = "Election"; break;
|
||||
case GetBackupListReq: val = "GetBackupListReq"; break;
|
||||
case GetBackupListResp: val = "GetBackupListResp"; break;
|
||||
case BecomeBackup: val = "BecomeBackup"; break;
|
||||
case DomainAnnouncement: val = "DomainAnnouncement"; break;
|
||||
case MasterAnnouncement: val = "MasterAnnouncement"; break;
|
||||
case ResetBrowserState: val = "ResetBrowserState"; break;
|
||||
case LocalMasterAnnouncement: val = "LocalMasterAnnouncement"; break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
handle incoming browse mailslot requests
|
||||
*/
|
||||
void nbtd_mailslot_browse_handler(struct dgram_mailslot_handler *dgmslot,
|
||||
struct nbt_dgram_packet *packet,
|
||||
struct socket_address *src)
|
||||
{
|
||||
struct nbt_browse_packet *browse = talloc(dgmslot, struct nbt_browse_packet);
|
||||
struct nbt_name *name = &packet->data.msg.dest_name;
|
||||
NTSTATUS status;
|
||||
|
||||
if (browse == NULL) {
|
||||
status = NT_STATUS_INVALID_PARAMETER;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
status = dgram_mailslot_browse_parse(dgmslot, browse, packet, browse);
|
||||
if (!NT_STATUS_IS_OK(status)) goto failed;
|
||||
|
||||
DEBUG(2,("Browse %s (Op %d) on '%s' '%s' from %s:%d\n",
|
||||
nbt_browse_opcode_string(browse->opcode), browse->opcode,
|
||||
nbt_name_string(browse, name), dgmslot->mailslot_name,
|
||||
src->addr, src->port));
|
||||
|
||||
if (DEBUGLEVEL >= 10) {
|
||||
NDR_PRINT_DEBUG(nbt_browse_packet, browse);
|
||||
}
|
||||
|
||||
talloc_free(browse);
|
||||
return;
|
||||
|
||||
failed:
|
||||
DEBUG(2,("nbtd browse handler failed from %s:%d to %s - %s\n",
|
||||
src->addr, src->port, nbt_name_string(browse, name),
|
||||
nt_errstr(status)));
|
||||
talloc_free(browse);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
NBT datagram netlogon server
|
||||
|
||||
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 "lib/socket/socket.h"
|
||||
#include "lib/ldb/include/ldb.h"
|
||||
#include "dsdb/samdb/samdb.h"
|
||||
#include "auth/auth.h"
|
||||
#include "db_wrap.h"
|
||||
#include "librpc/gen_ndr/ndr_nbt.h"
|
||||
|
||||
/*
|
||||
reply to a GETDC request
|
||||
*/
|
||||
static void nbtd_netlogon_getdc(struct dgram_mailslot_handler *dgmslot,
|
||||
struct nbtd_interface *iface,
|
||||
struct nbt_dgram_packet *packet,
|
||||
const struct socket_address *src,
|
||||
struct nbt_netlogon_packet *netlogon)
|
||||
{
|
||||
struct nbt_name *name = &packet->data.msg.dest_name;
|
||||
struct nbtd_interface *reply_iface = nbtd_find_reply_iface(iface, src->addr, False);
|
||||
struct nbt_netlogon_packet reply;
|
||||
struct nbt_netlogon_response_from_pdc *pdc;
|
||||
const char *ref_attrs[] = {"nETBIOSName", NULL};
|
||||
struct ldb_message **ref_res;
|
||||
struct ldb_context *samctx;
|
||||
struct ldb_dn *partitions_basedn;
|
||||
int ret;
|
||||
|
||||
/* only answer getdc requests on the PDC or LOGON names */
|
||||
if (name->type != NBT_NAME_PDC && name->type != NBT_NAME_LOGON) {
|
||||
return;
|
||||
}
|
||||
|
||||
samctx = samdb_connect(packet, anonymous_session(packet));
|
||||
if (samctx == NULL) {
|
||||
DEBUG(2,("Unable to open sam in getdc reply\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
partitions_basedn = samdb_partitions_dn(samctx, samctx);
|
||||
|
||||
ret = gendb_search(samctx, samctx, partitions_basedn, &ref_res, ref_attrs,
|
||||
"(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
|
||||
name->name);
|
||||
|
||||
if (ret != 1) {
|
||||
DEBUG(2,("Unable to find domain reference '%s' in sam\n", name->name));
|
||||
return;
|
||||
}
|
||||
|
||||
/* setup a GETDC reply */
|
||||
ZERO_STRUCT(reply);
|
||||
reply.command = NETLOGON_RESPONSE_FROM_PDC;
|
||||
pdc = &reply.req.response;
|
||||
|
||||
pdc->pdc_name = lp_netbios_name();
|
||||
pdc->unicode_pdc_name = pdc->pdc_name;
|
||||
pdc->domain_name = samdb_result_string(ref_res[0], "nETBIOSName", name->name);;
|
||||
pdc->nt_version = 1;
|
||||
pdc->lmnt_token = 0xFFFF;
|
||||
pdc->lm20_token = 0xFFFF;
|
||||
|
||||
|
||||
packet->data.msg.dest_name.type = 0;
|
||||
|
||||
dgram_mailslot_netlogon_reply(reply_iface->dgmsock,
|
||||
packet,
|
||||
netlogon->req.pdc.mailslot_name,
|
||||
&reply);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
reply to a ADS style GETDC request
|
||||
*/
|
||||
static void nbtd_netlogon_getdc2(struct dgram_mailslot_handler *dgmslot,
|
||||
struct nbtd_interface *iface,
|
||||
struct nbt_dgram_packet *packet,
|
||||
const struct socket_address *src,
|
||||
struct nbt_netlogon_packet *netlogon)
|
||||
{
|
||||
struct nbt_name *name = &packet->data.msg.dest_name;
|
||||
struct nbtd_interface *reply_iface = nbtd_find_reply_iface(iface, src->addr, False);
|
||||
struct nbt_netlogon_packet reply;
|
||||
struct nbt_netlogon_response_from_pdc2 *pdc;
|
||||
struct ldb_context *samctx;
|
||||
const char *ref_attrs[] = {"nETBIOSName", "dnsRoot", "ncName", NULL};
|
||||
const char *dom_attrs[] = {"objectGUID", NULL};
|
||||
struct ldb_message **ref_res, **dom_res;
|
||||
int ret;
|
||||
const char **services = lp_server_services();
|
||||
const char *my_ip = reply_iface->ip_address;
|
||||
struct ldb_dn *partitions_basedn;
|
||||
if (!my_ip) {
|
||||
DEBUG(0, ("Could not obtain own IP address for datagram socket\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* only answer getdc requests on the PDC or LOGON names */
|
||||
if (name->type != NBT_NAME_PDC && name->type != NBT_NAME_LOGON) {
|
||||
return;
|
||||
}
|
||||
|
||||
samctx = samdb_connect(packet, anonymous_session(packet));
|
||||
if (samctx == NULL) {
|
||||
DEBUG(2,("Unable to open sam in getdc reply\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
partitions_basedn = samdb_partitions_dn(samctx, samctx);
|
||||
|
||||
ret = gendb_search(samctx, samctx, partitions_basedn, &ref_res, ref_attrs,
|
||||
"(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
|
||||
name->name);
|
||||
|
||||
if (ret != 1) {
|
||||
DEBUG(2,("Unable to find domain reference '%s' in sam\n", name->name));
|
||||
return;
|
||||
}
|
||||
|
||||
/* try and find the domain */
|
||||
ret = gendb_search_dn(samctx, samctx,
|
||||
samdb_result_dn(samctx, samctx, ref_res[0], "ncName", NULL),
|
||||
&dom_res, dom_attrs);
|
||||
if (ret != 1) {
|
||||
DEBUG(2,("Unable to find domain from reference '%s' in sam\n",
|
||||
ldb_dn_get_linearized(ref_res[0]->dn)));
|
||||
return;
|
||||
}
|
||||
|
||||
/* setup a GETDC reply */
|
||||
ZERO_STRUCT(reply);
|
||||
reply.command = NETLOGON_RESPONSE_FROM_PDC2;
|
||||
|
||||
#if 0
|
||||
/* newer testing shows that the reply command type is not
|
||||
changed based on whether a username is given in the
|
||||
reply. This was what was causing the w2k join to be so
|
||||
slow */
|
||||
if (netlogon->req.pdc2.user_name[0]) {
|
||||
reply.command = NETLOGON_RESPONSE_FROM_PDC_USER;
|
||||
}
|
||||
#endif
|
||||
|
||||
pdc = &reply.req.response2;
|
||||
|
||||
/* TODO: accurately depict which services we are running */
|
||||
pdc->server_type =
|
||||
NBT_SERVER_PDC | NBT_SERVER_GC |
|
||||
NBT_SERVER_DS | NBT_SERVER_TIMESERV |
|
||||
NBT_SERVER_CLOSEST | NBT_SERVER_WRITABLE |
|
||||
NBT_SERVER_GOOD_TIMESERV;
|
||||
|
||||
/* hmm, probably a better way to do this */
|
||||
if (str_list_check(services, "ldap")) {
|
||||
pdc->server_type |= NBT_SERVER_LDAP;
|
||||
}
|
||||
|
||||
if (str_list_check(services, "kdc")) {
|
||||
pdc->server_type |= NBT_SERVER_KDC;
|
||||
}
|
||||
|
||||
pdc->domain_uuid = samdb_result_guid(dom_res[0], "objectGUID");
|
||||
pdc->forest = samdb_result_string(ref_res[0], "dnsRoot", lp_realm());
|
||||
pdc->dns_domain = samdb_result_string(ref_res[0], "dnsRoot", lp_realm());
|
||||
|
||||
/* TODO: get our full DNS name from somewhere else */
|
||||
pdc->pdc_dns_name = talloc_asprintf(packet, "%s.%s",
|
||||
strlower_talloc(packet, lp_netbios_name()),
|
||||
pdc->dns_domain);
|
||||
pdc->domain = samdb_result_string(ref_res[0], "nETBIOSName", name->name);;
|
||||
pdc->pdc_name = lp_netbios_name();
|
||||
pdc->user_name = netlogon->req.pdc2.user_name;
|
||||
/* TODO: we need to make sure these are in our DNS zone */
|
||||
pdc->server_site = "Default-First-Site-Name";
|
||||
pdc->client_site = "Default-First-Site-Name";
|
||||
pdc->unknown = 0x10; /* what is this? */
|
||||
pdc->unknown2 = 2; /* and this ... */
|
||||
pdc->pdc_ip = my_ip;
|
||||
pdc->nt_version = 13;
|
||||
pdc->lmnt_token = 0xFFFF;
|
||||
pdc->lm20_token = 0xFFFF;
|
||||
|
||||
packet->data.msg.dest_name.type = 0;
|
||||
|
||||
dgram_mailslot_netlogon_reply(reply_iface->dgmsock,
|
||||
packet,
|
||||
netlogon->req.pdc2.mailslot_name,
|
||||
&reply);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
handle incoming netlogon mailslot requests
|
||||
*/
|
||||
void nbtd_mailslot_netlogon_handler(struct dgram_mailslot_handler *dgmslot,
|
||||
struct nbt_dgram_packet *packet,
|
||||
struct socket_address *src)
|
||||
{
|
||||
NTSTATUS status = NT_STATUS_NO_MEMORY;
|
||||
struct nbtd_interface *iface =
|
||||
talloc_get_type(dgmslot->private, struct nbtd_interface);
|
||||
struct nbt_netlogon_packet *netlogon =
|
||||
talloc(dgmslot, struct nbt_netlogon_packet);
|
||||
struct nbtd_iface_name *iname;
|
||||
struct nbt_name *name = &packet->data.msg.dest_name;
|
||||
|
||||
if (netlogon == NULL) goto failed;
|
||||
|
||||
/*
|
||||
see if the we are listening on the destination netbios name
|
||||
*/
|
||||
iname = nbtd_find_iname(iface, name, 0);
|
||||
if (iname == NULL) {
|
||||
status = NT_STATUS_BAD_NETWORK_NAME;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
DEBUG(2,("netlogon request to %s from %s:%d\n",
|
||||
nbt_name_string(netlogon, name), src->addr, src->port));
|
||||
status = dgram_mailslot_netlogon_parse(dgmslot, netlogon, packet, netlogon);
|
||||
if (!NT_STATUS_IS_OK(status)) goto failed;
|
||||
|
||||
switch (netlogon->command) {
|
||||
case NETLOGON_QUERY_FOR_PDC:
|
||||
nbtd_netlogon_getdc(dgmslot, iface, packet, src, netlogon);
|
||||
break;
|
||||
case NETLOGON_QUERY_FOR_PDC2:
|
||||
nbtd_netlogon_getdc2(dgmslot, iface, packet, src, netlogon);
|
||||
break;
|
||||
default:
|
||||
DEBUG(2,("unknown netlogon op %d from %s:%d\n",
|
||||
netlogon->command, src->addr, src->port));
|
||||
NDR_PRINT_DEBUG(nbt_netlogon_packet, netlogon);
|
||||
break;
|
||||
}
|
||||
|
||||
talloc_free(netlogon);
|
||||
return;
|
||||
|
||||
failed:
|
||||
DEBUG(2,("nbtd netlogon handler failed from %s:%d to %s - %s\n",
|
||||
src->addr, src->port, nbt_name_string(netlogon, name),
|
||||
nt_errstr(status)));
|
||||
talloc_free(netlogon);
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
NBT datagram ntlogon server
|
||||
|
||||
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 "lib/socket/socket.h"
|
||||
#include "librpc/gen_ndr/ndr_nbt.h"
|
||||
|
||||
/*
|
||||
reply to a SAM LOGON request
|
||||
*/
|
||||
static void nbtd_ntlogon_sam_logon(struct dgram_mailslot_handler *dgmslot,
|
||||
struct nbtd_interface *iface,
|
||||
struct nbt_dgram_packet *packet,
|
||||
const struct socket_address *src,
|
||||
struct nbt_ntlogon_packet *ntlogon)
|
||||
{
|
||||
struct nbt_name *name = &packet->data.msg.dest_name;
|
||||
struct nbtd_interface *reply_iface = nbtd_find_reply_iface(iface, src->addr, False);
|
||||
struct nbt_ntlogon_packet reply;
|
||||
struct nbt_ntlogon_sam_logon_reply *logon;
|
||||
|
||||
/* only answer sam logon requests on the PDC or LOGON names */
|
||||
if (name->type != NBT_NAME_PDC && name->type != NBT_NAME_LOGON) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* setup a SAM LOGON reply */
|
||||
ZERO_STRUCT(reply);
|
||||
reply.command = NTLOGON_SAM_LOGON_REPLY;
|
||||
logon = &reply.req.reply;
|
||||
|
||||
logon->server = talloc_asprintf(packet, "\\\\%s", lp_netbios_name());
|
||||
logon->user_name = ntlogon->req.logon.user_name;
|
||||
logon->domain = lp_workgroup();
|
||||
logon->nt_version = 1;
|
||||
logon->lmnt_token = 0xFFFF;
|
||||
logon->lm20_token = 0xFFFF;
|
||||
|
||||
packet->data.msg.dest_name.type = 0;
|
||||
|
||||
dgram_mailslot_ntlogon_reply(reply_iface->dgmsock,
|
||||
packet,
|
||||
ntlogon->req.logon.mailslot_name,
|
||||
&reply);
|
||||
}
|
||||
|
||||
/*
|
||||
handle incoming ntlogon mailslot requests
|
||||
*/
|
||||
void nbtd_mailslot_ntlogon_handler(struct dgram_mailslot_handler *dgmslot,
|
||||
struct nbt_dgram_packet *packet,
|
||||
struct socket_address *src)
|
||||
{
|
||||
NTSTATUS status = NT_STATUS_NO_MEMORY;
|
||||
struct nbtd_interface *iface =
|
||||
talloc_get_type(dgmslot->private, struct nbtd_interface);
|
||||
struct nbt_ntlogon_packet *ntlogon =
|
||||
talloc(dgmslot, struct nbt_ntlogon_packet);
|
||||
struct nbtd_iface_name *iname;
|
||||
struct nbt_name *name = &packet->data.msg.dest_name;
|
||||
|
||||
if (ntlogon == NULL) goto failed;
|
||||
|
||||
/*
|
||||
see if the we are listening on the destination netbios name
|
||||
*/
|
||||
iname = nbtd_find_iname(iface, name, 0);
|
||||
if (iname == NULL) {
|
||||
status = NT_STATUS_BAD_NETWORK_NAME;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
DEBUG(2,("ntlogon request to %s from %s:%d\n",
|
||||
nbt_name_string(ntlogon, name), src->addr, src->port));
|
||||
status = dgram_mailslot_ntlogon_parse(dgmslot, ntlogon, packet, ntlogon);
|
||||
if (!NT_STATUS_IS_OK(status)) goto failed;
|
||||
|
||||
NDR_PRINT_DEBUG(nbt_ntlogon_packet, ntlogon);
|
||||
|
||||
switch (ntlogon->command) {
|
||||
case NTLOGON_SAM_LOGON:
|
||||
nbtd_ntlogon_sam_logon(dgmslot, iface, packet, src, ntlogon);
|
||||
break;
|
||||
default:
|
||||
DEBUG(2,("unknown ntlogon op %d from %s:%d\n",
|
||||
ntlogon->command, src->addr, src->port));
|
||||
break;
|
||||
}
|
||||
|
||||
talloc_free(ntlogon);
|
||||
return;
|
||||
|
||||
failed:
|
||||
DEBUG(2,("nbtd ntlogon handler failed from %s:%d to %s - %s\n",
|
||||
src->addr, src->port, nbt_name_string(ntlogon, name),
|
||||
nt_errstr(status)));
|
||||
talloc_free(ntlogon);
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
NBT datagram server
|
||||
|
||||
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 "smbd/service_task.h"
|
||||
#include "lib/socket/socket.h"
|
||||
#include "libcli/resolve/resolve.h"
|
||||
#include "nbt_server/dgram/proto.h"
|
||||
#include "librpc/gen_ndr/ndr_nbt.h"
|
||||
|
||||
/*
|
||||
a list of mailslots that we have static handlers for
|
||||
*/
|
||||
static const struct {
|
||||
const char *mailslot_name;
|
||||
dgram_mailslot_handler_t handler;
|
||||
} mailslot_handlers[] = {
|
||||
{ NBT_MAILSLOT_NETLOGON, nbtd_mailslot_netlogon_handler },
|
||||
{ NBT_MAILSLOT_NTLOGON, nbtd_mailslot_ntlogon_handler },
|
||||
{ NBT_MAILSLOT_BROWSE, nbtd_mailslot_browse_handler }
|
||||
};
|
||||
|
||||
/*
|
||||
receive an incoming dgram request. This is used for general datagram
|
||||
requests. Mailslot requests for our listening mailslots
|
||||
are handled in the specific mailslot handlers
|
||||
*/
|
||||
void dgram_request_handler(struct nbt_dgram_socket *dgmsock,
|
||||
struct nbt_dgram_packet *packet,
|
||||
struct socket_address *src)
|
||||
{
|
||||
DEBUG(0,("General datagram request from %s:%d\n", src->addr, src->port));
|
||||
NDR_PRINT_DEBUG(nbt_dgram_packet, packet);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
setup the port 138 datagram listener for a given interface
|
||||
*/
|
||||
NTSTATUS nbtd_dgram_setup(struct nbtd_interface *iface, const char *bind_address)
|
||||
{
|
||||
struct nbt_dgram_socket *bcast_dgmsock = NULL;
|
||||
struct nbtd_server *nbtsrv = iface->nbtsrv;
|
||||
struct socket_address *bcast_addr, *bind_addr;
|
||||
NTSTATUS status;
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(iface);
|
||||
/* the list of mailslots that we are interested in */
|
||||
int i;
|
||||
|
||||
if (!tmp_ctx) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (strcmp("0.0.0.0", iface->netmask) != 0) {
|
||||
/* listen for broadcasts on port 138 */
|
||||
bcast_dgmsock = nbt_dgram_socket_init(iface, nbtsrv->task->event_ctx);
|
||||
if (!bcast_dgmsock) {
|
||||
talloc_free(tmp_ctx);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
bcast_addr = socket_address_from_strings(tmp_ctx, bcast_dgmsock->sock->backend_name,
|
||||
iface->bcast_address, lp_dgram_port());
|
||||
if (!bcast_addr) {
|
||||
talloc_free(tmp_ctx);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
status = socket_listen(bcast_dgmsock->sock, bcast_addr, 0, 0);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
talloc_free(tmp_ctx);
|
||||
DEBUG(0,("Failed to bind to %s:%d - %s\n",
|
||||
iface->bcast_address, lp_dgram_port(), nt_errstr(status)));
|
||||
return status;
|
||||
}
|
||||
|
||||
dgram_set_incoming_handler(bcast_dgmsock, dgram_request_handler, iface);
|
||||
}
|
||||
|
||||
/* listen for unicasts on port 138 */
|
||||
iface->dgmsock = nbt_dgram_socket_init(iface, nbtsrv->task->event_ctx);
|
||||
if (!iface->dgmsock) {
|
||||
talloc_free(tmp_ctx);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
bind_addr = socket_address_from_strings(tmp_ctx, iface->dgmsock->sock->backend_name,
|
||||
bind_address, lp_dgram_port());
|
||||
if (!bind_addr) {
|
||||
talloc_free(tmp_ctx);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
status = socket_listen(iface->dgmsock->sock, bind_addr, 0, 0);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
talloc_free(tmp_ctx);
|
||||
DEBUG(0,("Failed to bind to %s:%d - %s\n",
|
||||
bind_address, lp_dgram_port(), nt_errstr(status)));
|
||||
return status;
|
||||
}
|
||||
|
||||
dgram_set_incoming_handler(iface->dgmsock, dgram_request_handler, iface);
|
||||
|
||||
talloc_free(tmp_ctx);
|
||||
|
||||
for (i=0;i<ARRAY_SIZE(mailslot_handlers);i++) {
|
||||
/* note that we don't need to keep the pointer
|
||||
to the dgmslot around - the callback is all
|
||||
we need */
|
||||
struct dgram_mailslot_handler *dgmslot;
|
||||
|
||||
if (bcast_dgmsock) {
|
||||
dgmslot = dgram_mailslot_listen(bcast_dgmsock,
|
||||
mailslot_handlers[i].mailslot_name,
|
||||
mailslot_handlers[i].handler, iface);
|
||||
NT_STATUS_HAVE_NO_MEMORY(dgmslot);
|
||||
}
|
||||
|
||||
dgmslot = dgram_mailslot_listen(iface->dgmsock,
|
||||
mailslot_handlers[i].mailslot_name,
|
||||
mailslot_handlers[i].handler, iface);
|
||||
NT_STATUS_HAVE_NO_MEMORY(dgmslot);
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
NBT interface handling
|
||||
|
||||
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/util/dlinklist.h"
|
||||
#include "nbt_server/nbt_server.h"
|
||||
#include "smbd/service_task.h"
|
||||
#include "lib/socket/socket.h"
|
||||
#include "nbt_server/wins/winsserver.h"
|
||||
#include "nbt_server/dgram/proto.h"
|
||||
#include "system/network.h"
|
||||
#include "lib/socket/netif.h"
|
||||
|
||||
|
||||
/*
|
||||
receive an incoming request and dispatch it to the right place
|
||||
*/
|
||||
static void nbtd_request_handler(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 nbtd_server *nbtsrv = iface->nbtsrv;
|
||||
|
||||
nbtsrv->stats.total_received++;
|
||||
|
||||
/* see if its from one of our own interfaces - if so, then ignore it */
|
||||
if (nbtd_self_packet_and_bcast(nbtsock, packet, src)) {
|
||||
DEBUG(10,("Ignoring bcast self packet from %s:%d\n", src->addr, src->port));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (packet->operation & NBT_OPCODE) {
|
||||
case NBT_OPCODE_QUERY:
|
||||
nbtsrv->stats.query_count++;
|
||||
nbtd_request_query(nbtsock, packet, src);
|
||||
break;
|
||||
|
||||
case NBT_OPCODE_REGISTER:
|
||||
case NBT_OPCODE_REFRESH:
|
||||
case NBT_OPCODE_REFRESH2:
|
||||
nbtsrv->stats.register_count++;
|
||||
nbtd_request_defense(nbtsock, packet, src);
|
||||
break;
|
||||
|
||||
case NBT_OPCODE_RELEASE:
|
||||
case NBT_OPCODE_MULTI_HOME_REG:
|
||||
nbtsrv->stats.release_count++;
|
||||
nbtd_winsserver_request(nbtsock, packet, src);
|
||||
break;
|
||||
|
||||
default:
|
||||
nbtd_bad_packet(packet, src, "Unexpected opcode");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
find a registered name on an interface
|
||||
*/
|
||||
struct nbtd_iface_name *nbtd_find_iname(struct nbtd_interface *iface,
|
||||
struct nbt_name *name,
|
||||
uint16_t nb_flags)
|
||||
{
|
||||
struct nbtd_iface_name *iname;
|
||||
for (iname=iface->names;iname;iname=iname->next) {
|
||||
if (iname->name.type == name->type &&
|
||||
strcmp(name->name, iname->name.name) == 0 &&
|
||||
((iname->nb_flags & nb_flags) == nb_flags)) {
|
||||
return iname;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
start listening on the given address
|
||||
*/
|
||||
static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv,
|
||||
const char *bind_address,
|
||||
const char *address,
|
||||
const char *bcast,
|
||||
const char *netmask)
|
||||
{
|
||||
struct nbtd_interface *iface;
|
||||
NTSTATUS status;
|
||||
struct socket_address *bcast_address;
|
||||
struct socket_address *unicast_address;
|
||||
|
||||
/*
|
||||
we actually create two sockets. One listens on the broadcast address
|
||||
for the interface, and the other listens on our specific address. This
|
||||
allows us to run with "bind interfaces only" while still receiving
|
||||
broadcast addresses, and also simplifies matching incoming requests
|
||||
to interfaces
|
||||
*/
|
||||
|
||||
iface = talloc(nbtsrv, struct nbtd_interface);
|
||||
NT_STATUS_HAVE_NO_MEMORY(iface);
|
||||
|
||||
iface->nbtsrv = nbtsrv;
|
||||
iface->bcast_address = talloc_steal(iface, bcast);
|
||||
iface->ip_address = talloc_steal(iface, address);
|
||||
iface->netmask = talloc_steal(iface, netmask);
|
||||
iface->names = NULL;
|
||||
|
||||
if (strcmp(netmask, "0.0.0.0") != 0) {
|
||||
struct nbt_name_socket *bcast_nbtsock;
|
||||
|
||||
/* listen for broadcasts on port 137 */
|
||||
bcast_nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
|
||||
if (!bcast_nbtsock) {
|
||||
talloc_free(iface);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
bcast_address = socket_address_from_strings(bcast_nbtsock, bcast_nbtsock->sock->backend_name,
|
||||
bcast, lp_nbt_port());
|
||||
if (!bcast_address) {
|
||||
talloc_free(iface);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
status = socket_listen(bcast_nbtsock->sock, bcast_address, 0, 0);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("Failed to bind to %s:%d - %s\n",
|
||||
bcast, lp_nbt_port(), nt_errstr(status)));
|
||||
talloc_free(iface);
|
||||
return status;
|
||||
}
|
||||
talloc_free(bcast_address);
|
||||
|
||||
nbt_set_incoming_handler(bcast_nbtsock, nbtd_request_handler, iface);
|
||||
}
|
||||
|
||||
/* listen for unicasts on port 137 */
|
||||
iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
|
||||
if (!iface->nbtsock) {
|
||||
talloc_free(iface);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
unicast_address = socket_address_from_strings(iface->nbtsock, iface->nbtsock->sock->backend_name,
|
||||
bind_address, lp_nbt_port());
|
||||
|
||||
status = socket_listen(iface->nbtsock->sock, unicast_address, 0, 0);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("Failed to bind to %s:%d - %s\n",
|
||||
bind_address, lp_nbt_port(), nt_errstr(status)));
|
||||
talloc_free(iface);
|
||||
return status;
|
||||
}
|
||||
talloc_free(unicast_address);
|
||||
|
||||
nbt_set_incoming_handler(iface->nbtsock, nbtd_request_handler, iface);
|
||||
|
||||
/* also setup the datagram listeners */
|
||||
status = nbtd_dgram_setup(iface, bind_address);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0,("Failed to setup dgram listen on %s - %s\n",
|
||||
bind_address, nt_errstr(status)));
|
||||
talloc_free(iface);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (strcmp(netmask, "0.0.0.0") == 0) {
|
||||
DLIST_ADD(nbtsrv->bcast_interface, iface);
|
||||
} else {
|
||||
DLIST_ADD(nbtsrv->interfaces, iface);
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
setup a socket for talking to our WINS servers
|
||||
*/
|
||||
static NTSTATUS nbtd_add_wins_socket(struct nbtd_server *nbtsrv)
|
||||
{
|
||||
struct nbtd_interface *iface;
|
||||
|
||||
iface = talloc_zero(nbtsrv, struct nbtd_interface);
|
||||
NT_STATUS_HAVE_NO_MEMORY(iface);
|
||||
|
||||
iface->nbtsrv = nbtsrv;
|
||||
|
||||
DLIST_ADD(nbtsrv->wins_interface, iface);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
setup our listening sockets on the configured network interfaces
|
||||
*/
|
||||
NTSTATUS nbtd_startup_interfaces(struct nbtd_server *nbtsrv)
|
||||
{
|
||||
int num_interfaces = iface_count();
|
||||
int i;
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(nbtsrv);
|
||||
NTSTATUS status;
|
||||
|
||||
/* if we are allowing incoming packets from any address, then
|
||||
we also need to bind to the wildcard address */
|
||||
if (!lp_bind_interfaces_only()) {
|
||||
const char *primary_address;
|
||||
|
||||
/* the primary address is the address we will return
|
||||
for non-WINS queries not made on a specific
|
||||
interface */
|
||||
if (num_interfaces > 0) {
|
||||
primary_address = iface_n_ip(0);
|
||||
} else {
|
||||
primary_address = sys_inet_ntoa(interpret_addr2(
|
||||
lp_netbios_name()));
|
||||
}
|
||||
primary_address = talloc_strdup(tmp_ctx, primary_address);
|
||||
NT_STATUS_HAVE_NO_MEMORY(primary_address);
|
||||
|
||||
status = nbtd_add_socket(nbtsrv,
|
||||
"0.0.0.0",
|
||||
primary_address,
|
||||
talloc_strdup(tmp_ctx, "255.255.255.255"),
|
||||
talloc_strdup(tmp_ctx, "0.0.0.0"));
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
}
|
||||
|
||||
for (i=0; i<num_interfaces; i++) {
|
||||
const char *bcast = iface_n_bcast(i);
|
||||
const char *address, *netmask;
|
||||
|
||||
/* we can't assume every interface is broadcast capable */
|
||||
if (bcast == NULL) continue;
|
||||
|
||||
address = talloc_strdup(tmp_ctx, iface_n_ip(i));
|
||||
bcast = talloc_strdup(tmp_ctx, bcast);
|
||||
netmask = talloc_strdup(tmp_ctx, iface_n_netmask(i));
|
||||
|
||||
status = nbtd_add_socket(nbtsrv, address, address, bcast, netmask);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
}
|
||||
|
||||
if (lp_wins_server_list()) {
|
||||
status = nbtd_add_wins_socket(nbtsrv);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
}
|
||||
|
||||
talloc_free(tmp_ctx);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
form a list of addresses that we should use in name query replies
|
||||
we always place the IP in the given interface first
|
||||
*/
|
||||
const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
struct nbtd_server *nbtsrv = iface->nbtsrv;
|
||||
const char **ret = NULL;
|
||||
struct nbtd_interface *iface2;
|
||||
BOOL is_loopback = False;
|
||||
|
||||
if (iface->ip_address) {
|
||||
is_loopback = iface_same_net(iface->ip_address, "127.0.0.1", "255.0.0.0");
|
||||
ret = str_list_add(ret, iface->ip_address);
|
||||
}
|
||||
|
||||
for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
|
||||
if (iface2 == iface) continue;
|
||||
|
||||
if (!iface2->ip_address) continue;
|
||||
|
||||
if (!is_loopback) {
|
||||
if (iface_same_net(iface2->ip_address, "127.0.0.1", "255.0.0.0")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ret = str_list_add(ret, iface2->ip_address);
|
||||
}
|
||||
|
||||
talloc_steal(mem_ctx, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
find the interface to use for sending a outgoing request
|
||||
*/
|
||||
struct nbtd_interface *nbtd_find_request_iface(struct nbtd_server *nbtd_server,
|
||||
const char *address, BOOL allow_bcast_iface)
|
||||
{
|
||||
struct nbtd_interface *cur;
|
||||
|
||||
/* try to find a exact match */
|
||||
for (cur=nbtd_server->interfaces;cur;cur=cur->next) {
|
||||
if (iface_same_net(address, cur->ip_address, cur->netmask)) {
|
||||
return cur;
|
||||
}
|
||||
}
|
||||
|
||||
/* no exact match, if we have the broadcast interface, use that */
|
||||
if (allow_bcast_iface && nbtd_server->bcast_interface) {
|
||||
return nbtd_server->bcast_interface;
|
||||
}
|
||||
|
||||
/* fallback to first interface */
|
||||
return nbtd_server->interfaces;
|
||||
}
|
||||
|
||||
/*
|
||||
* find the interface to use for sending a outgoing reply
|
||||
*/
|
||||
struct nbtd_interface *nbtd_find_reply_iface(struct nbtd_interface *iface,
|
||||
const char *address, BOOL allow_bcast_iface)
|
||||
{
|
||||
struct nbtd_server *nbtd_server = iface->nbtsrv;
|
||||
|
||||
/* first try to use the given interfacel when it's not the broadcast one */
|
||||
if (iface != nbtd_server->bcast_interface) {
|
||||
return iface;
|
||||
}
|
||||
|
||||
return nbtd_find_request_iface(nbtd_server, address, allow_bcast_iface);
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
irpc services for the NBT server
|
||||
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
Copyright (C) Volker Lendecke 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 "smbd/service_task.h"
|
||||
#include "smbd/service.h"
|
||||
#include "nbt_server/nbt_server.h"
|
||||
#include "nbt_server/wins/winsserver.h"
|
||||
#include "librpc/gen_ndr/ndr_irpc.h"
|
||||
#include "lib/socket/socket.h"
|
||||
#include "libcli/resolve/resolve.h"
|
||||
#include "librpc/gen_ndr/ndr_nbt.h"
|
||||
|
||||
/*
|
||||
serve out the nbt statistics
|
||||
*/
|
||||
static NTSTATUS nbtd_information(struct irpc_message *msg,
|
||||
struct nbtd_information *r)
|
||||
{
|
||||
struct nbtd_server *server = talloc_get_type(msg->private, struct nbtd_server);
|
||||
|
||||
switch (r->in.level) {
|
||||
case NBTD_INFO_STATISTICS:
|
||||
r->out.info.stats = &server->stats;
|
||||
break;
|
||||
}
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
winbind needs to be able to do a getdc request, but some windows
|
||||
servers always send the reply to port 138, regardless of the request
|
||||
port. To cope with this we use a irpc request to the NBT server
|
||||
which has port 138 open, and thus can receive the replies
|
||||
*/
|
||||
struct getdc_state {
|
||||
struct irpc_message *msg;
|
||||
struct nbtd_getdcname *req;
|
||||
};
|
||||
|
||||
static void getdc_recv_ntlogon_reply(struct dgram_mailslot_handler *dgmslot,
|
||||
struct nbt_dgram_packet *packet,
|
||||
struct socket_address *src)
|
||||
{
|
||||
struct getdc_state *s =
|
||||
talloc_get_type(dgmslot->private, struct getdc_state);
|
||||
|
||||
struct nbt_ntlogon_packet ntlogon;
|
||||
NTSTATUS status;
|
||||
|
||||
status = dgram_mailslot_ntlogon_parse(dgmslot, packet, packet,
|
||||
&ntlogon);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(5, ("dgram_mailslot_ntlogon_parse failed: %s\n",
|
||||
nt_errstr(status)));
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = NT_STATUS_NO_LOGON_SERVERS;
|
||||
|
||||
DEBUG(10, ("reply: command=%d\n", ntlogon.command));
|
||||
|
||||
switch (ntlogon.command) {
|
||||
case NTLOGON_SAM_LOGON:
|
||||
DEBUG(0, ("Huh -- got NTLOGON_SAM_LOGON as reply\n"));
|
||||
break;
|
||||
case NTLOGON_SAM_LOGON_REPLY:
|
||||
case NTLOGON_SAM_LOGON_REPLY15: {
|
||||
const char *p = ntlogon.req.reply.server;
|
||||
|
||||
DEBUG(10, ("NTLOGON_SAM_LOGON_REPLY: server: %s, user: %s, "
|
||||
"domain: %s\n", p, ntlogon.req.reply.user_name,
|
||||
ntlogon.req.reply.domain));
|
||||
|
||||
if (*p == '\\') p += 1;
|
||||
if (*p == '\\') p += 1;
|
||||
|
||||
s->req->out.dcname = talloc_strdup(s->req, p);
|
||||
if (s->req->out.dcname == NULL) {
|
||||
DEBUG(0, ("talloc failed\n"));
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
status = NT_STATUS_OK;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DEBUG(0, ("Got unknown packet: %d\n", ntlogon.command));
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
irpc_send_reply(s->msg, status);
|
||||
}
|
||||
|
||||
static NTSTATUS nbtd_getdcname(struct irpc_message *msg,
|
||||
struct nbtd_getdcname *req)
|
||||
{
|
||||
struct nbtd_server *server =
|
||||
talloc_get_type(msg->private, struct nbtd_server);
|
||||
struct nbtd_interface *iface = nbtd_find_request_iface(server, req->in.ip_address, True);
|
||||
struct getdc_state *s;
|
||||
struct nbt_ntlogon_packet p;
|
||||
struct nbt_ntlogon_sam_logon *r;
|
||||
struct nbt_name src, dst;
|
||||
struct socket_address *dest;
|
||||
struct dgram_mailslot_handler *handler;
|
||||
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
|
||||
|
||||
DEBUG(0, ("nbtd_getdcname called\n"));
|
||||
|
||||
s = talloc(msg, struct getdc_state);
|
||||
NT_STATUS_HAVE_NO_MEMORY(s);
|
||||
|
||||
s->msg = msg;
|
||||
s->req = req;
|
||||
|
||||
handler = dgram_mailslot_temp(iface->dgmsock, NBT_MAILSLOT_GETDC,
|
||||
getdc_recv_ntlogon_reply, s);
|
||||
NT_STATUS_HAVE_NO_MEMORY(handler);
|
||||
|
||||
ZERO_STRUCT(p);
|
||||
p.command = NTLOGON_SAM_LOGON;
|
||||
r = &p.req.logon;
|
||||
r->request_count = 0;
|
||||
r->computer_name = req->in.my_computername;
|
||||
r->user_name = req->in.my_accountname;
|
||||
r->mailslot_name = handler->mailslot_name;
|
||||
r->acct_control = req->in.account_control;
|
||||
r->sid = *req->in.domain_sid;
|
||||
r->nt_version = 1;
|
||||
r->lmnt_token = 0xffff;
|
||||
r->lm20_token = 0xffff;
|
||||
|
||||
make_nbt_name_client(&src, req->in.my_computername);
|
||||
make_nbt_name(&dst, req->in.domainname, 0x1c);
|
||||
|
||||
dest = socket_address_from_strings(msg, iface->dgmsock->sock->backend_name,
|
||||
req->in.ip_address, 138);
|
||||
NT_STATUS_HAVE_NO_MEMORY(dest);
|
||||
|
||||
status = dgram_mailslot_ntlogon_send(iface->dgmsock, DGRAM_DIRECT_GROUP,
|
||||
&dst, dest,
|
||||
&src, &p);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(0, ("dgram_mailslot_ntlogon_send failed: %s\n",
|
||||
nt_errstr(status)));
|
||||
return status;
|
||||
}
|
||||
|
||||
msg->defer_reply = True;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
register the irpc handlers for the nbt server
|
||||
*/
|
||||
void nbtd_register_irpc(struct nbtd_server *nbtsrv)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct task_server *task = nbtsrv->task;
|
||||
|
||||
status = IRPC_REGISTER(task->msg_ctx, irpc, NBTD_INFORMATION,
|
||||
nbtd_information, nbtsrv);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
task_server_terminate(task, "nbtd failed to setup monitoring");
|
||||
return;
|
||||
}
|
||||
|
||||
status = IRPC_REGISTER(task->msg_ctx, irpc, NBTD_GETDCNAME,
|
||||
nbtd_getdcname, nbtsrv);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
task_server_terminate(task, "nbtd failed to setup getdcname "
|
||||
"handler");
|
||||
return;
|
||||
}
|
||||
|
||||
status = IRPC_REGISTER(task->msg_ctx, irpc, NBTD_PROXY_WINS_CHALLENGE,
|
||||
nbtd_proxy_wins_challenge, nbtsrv);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
task_server_terminate(task, "nbtd failed to setup wins challenge "
|
||||
"handler");
|
||||
return;
|
||||
}
|
||||
|
||||
status = IRPC_REGISTER(task->msg_ctx, irpc, NBTD_PROXY_WINS_RELEASE_DEMAND,
|
||||
nbtd_proxy_wins_release_demand, nbtsrv);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
task_server_terminate(task, "nbtd failed to setup wins release demand "
|
||||
"handler");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
NBT server task
|
||||
|
||||
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 "smbd/service_task.h"
|
||||
#include "smbd/service.h"
|
||||
#include "nbt_server/nbt_server.h"
|
||||
#include "nbt_server/wins/winsserver.h"
|
||||
#include "system/network.h"
|
||||
#include "lib/socket/netif.h"
|
||||
|
||||
/*
|
||||
startup the nbtd task
|
||||
*/
|
||||
static void nbtd_task_init(struct task_server *task)
|
||||
{
|
||||
struct nbtd_server *nbtsrv;
|
||||
NTSTATUS status;
|
||||
|
||||
if (iface_count() == 0) {
|
||||
task_server_terminate(task, "nbtd: no network interfaces configured");
|
||||
return;
|
||||
}
|
||||
|
||||
task_server_set_title(task, "task[nbtd]");
|
||||
|
||||
nbtsrv = talloc(task, struct nbtd_server);
|
||||
if (nbtsrv == NULL) {
|
||||
task_server_terminate(task, "nbtd: out of memory");
|
||||
return;
|
||||
}
|
||||
|
||||
nbtsrv->task = task;
|
||||
nbtsrv->interfaces = NULL;
|
||||
nbtsrv->bcast_interface = NULL;
|
||||
nbtsrv->wins_interface = NULL;
|
||||
|
||||
/* start listening on the configured network interfaces */
|
||||
status = nbtd_startup_interfaces(nbtsrv);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
task_server_terminate(task, "nbtd failed to setup interfaces");
|
||||
return;
|
||||
}
|
||||
|
||||
/* start the WINS server, if appropriate */
|
||||
status = nbtd_winsserver_init(nbtsrv);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
task_server_terminate(task, "nbtd failed to start WINS server");
|
||||
return;
|
||||
}
|
||||
|
||||
nbtd_register_irpc(nbtsrv);
|
||||
|
||||
/* start the process of registering our names on all interfaces */
|
||||
nbtd_register_names(nbtsrv);
|
||||
|
||||
irpc_add_name(task->msg_ctx, "nbt_server");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
initialise the nbt server
|
||||
*/
|
||||
static NTSTATUS nbtd_init(struct event_context *event_ctx, const struct model_ops *model_ops)
|
||||
{
|
||||
return task_server_startup(event_ctx, model_ops, nbtd_task_init);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
register ourselves as a available server
|
||||
*/
|
||||
NTSTATUS server_service_nbtd_init(void)
|
||||
{
|
||||
return register_server_service("nbt", nbtd_init);
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
NBT 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.
|
||||
*/
|
||||
|
||||
#include "libcli/nbt/libnbt.h"
|
||||
#include "libcli/wrepl/winsrepl.h"
|
||||
#include "libcli/dgram/libdgram.h"
|
||||
#include "librpc/gen_ndr/irpc.h"
|
||||
#include "lib/messaging/irpc.h"
|
||||
|
||||
/*
|
||||
a list of our registered names on each interface
|
||||
*/
|
||||
struct nbtd_iface_name {
|
||||
struct nbtd_iface_name *next, *prev;
|
||||
struct nbtd_interface *iface;
|
||||
struct nbt_name name;
|
||||
uint16_t nb_flags;
|
||||
struct timeval registration_time;
|
||||
uint32_t ttl;
|
||||
|
||||
/* if registered with a wins server, then this lists the server being
|
||||
used */
|
||||
const char *wins_server;
|
||||
};
|
||||
|
||||
|
||||
/* a list of network interfaces we are listening on */
|
||||
struct nbtd_interface {
|
||||
struct nbtd_interface *next, *prev;
|
||||
struct nbtd_server *nbtsrv;
|
||||
const char *ip_address;
|
||||
const char *bcast_address;
|
||||
const char *netmask;
|
||||
struct nbt_name_socket *nbtsock;
|
||||
struct nbt_dgram_socket *dgmsock;
|
||||
struct nbtd_iface_name *names;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
top level context structure for the nbt server
|
||||
*/
|
||||
struct nbtd_server {
|
||||
struct task_server *task;
|
||||
|
||||
/* the list of local network interfaces */
|
||||
struct nbtd_interface *interfaces;
|
||||
|
||||
/* broadcast interface used for receiving packets only */
|
||||
struct nbtd_interface *bcast_interface;
|
||||
|
||||
/* wins client interface - used for registering and refreshing
|
||||
our names with a WINS server */
|
||||
struct nbtd_interface *wins_interface;
|
||||
|
||||
struct wins_server *winssrv;
|
||||
|
||||
struct nbtd_statistics stats;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* check a condition on an incoming packet */
|
||||
#define NBTD_ASSERT_PACKET(packet, src, test) do { \
|
||||
if (!(test)) { \
|
||||
nbtd_bad_packet(packet, src, #test); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#include "nbt_server/nbt_server_proto.h"
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
answer node status queries
|
||||
|
||||
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/util/dlinklist.h"
|
||||
#include "system/network.h"
|
||||
#include "nbt_server/nbt_server.h"
|
||||
#include "lib/socket/socket.h"
|
||||
#include "librpc/gen_ndr/ndr_nbt.h"
|
||||
|
||||
/*
|
||||
send a name status reply
|
||||
*/
|
||||
static void nbtd_node_status_reply(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *request_packet,
|
||||
struct socket_address *src,
|
||||
struct nbt_name *name,
|
||||
struct nbtd_interface *iface)
|
||||
{
|
||||
struct nbt_name_packet *packet;
|
||||
uint32_t name_count;
|
||||
struct nbtd_iface_name *iname;
|
||||
struct nbtd_server *nbtsrv = iface->nbtsrv;
|
||||
|
||||
/* work out how many names to send */
|
||||
name_count = 0;
|
||||
for (iname=iface->names;iname;iname=iname->next) {
|
||||
if ((iname->nb_flags & NBT_NM_ACTIVE) &&
|
||||
strcmp(iname->name.name, "*") != 0) {
|
||||
name_count++;
|
||||
}
|
||||
}
|
||||
|
||||
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_OPCODE_QUERY | NBT_FLAG_REPLY | NBT_FLAG_AUTHORITIVE;
|
||||
|
||||
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_STATUS;
|
||||
packet->answers[0].rr_class = NBT_QCLASS_IP;
|
||||
packet->answers[0].ttl = 0;
|
||||
packet->answers[0].rdata.status.num_names = name_count;
|
||||
packet->answers[0].rdata.status.names = talloc_array(packet->answers,
|
||||
struct nbt_status_name, name_count);
|
||||
if (packet->answers[0].rdata.status.names == NULL) goto failed;
|
||||
|
||||
name_count = 0;
|
||||
for (iname=iface->names;iname;iname=iname->next) {
|
||||
if ((iname->nb_flags & NBT_NM_ACTIVE) &&
|
||||
strcmp(iname->name.name, "*") != 0) {
|
||||
struct nbt_status_name *n = &packet->answers[0].rdata.status.names[name_count];
|
||||
n->name = talloc_asprintf(packet->answers, "%-15s", iname->name.name);
|
||||
if (n->name == NULL) goto failed;
|
||||
n->type = iname->name.type;
|
||||
n->nb_flags = iname->nb_flags;
|
||||
name_count++;
|
||||
}
|
||||
}
|
||||
/* we deliberately don't fill in the statistics structure as
|
||||
it could lead to giving attackers too much information */
|
||||
ZERO_STRUCT(packet->answers[0].rdata.status.statistics);
|
||||
|
||||
DEBUG(7,("Sending node status reply for %s to %s:%d\n",
|
||||
nbt_name_string(packet, name), src->addr, src->port));
|
||||
|
||||
nbtsrv->stats.total_sent++;
|
||||
nbt_name_reply_send(nbtsock, src, packet);
|
||||
|
||||
failed:
|
||||
talloc_free(packet);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
answer a node status query
|
||||
*/
|
||||
void nbtd_query_status(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *packet,
|
||||
struct socket_address *src)
|
||||
{
|
||||
struct nbt_name *name;
|
||||
struct nbtd_iface_name *iname;
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
|
||||
NBTD_ASSERT_PACKET(packet, src, packet->qdcount == 1);
|
||||
NBTD_ASSERT_PACKET(packet, src, packet->questions[0].question_type == NBT_QTYPE_STATUS);
|
||||
NBTD_ASSERT_PACKET(packet, src, packet->questions[0].question_class == NBT_QCLASS_IP);
|
||||
|
||||
/* see if we have the requested name on this interface */
|
||||
name = &packet->questions[0].name;
|
||||
|
||||
iname = nbtd_find_iname(iface, name, NBT_NM_ACTIVE);
|
||||
if (iname == NULL) {
|
||||
DEBUG(7,("Node status query for %s from %s - not found on %s\n",
|
||||
nbt_name_string(packet, name), src->addr, iface->ip_address));
|
||||
return;
|
||||
}
|
||||
|
||||
nbtd_node_status_reply(nbtsock, packet, src,
|
||||
&iname->name, iface);
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
packet utility functions
|
||||
|
||||
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 "lib/socket/socket.h"
|
||||
#include "librpc/gen_ndr/ndr_nbt.h"
|
||||
|
||||
/*
|
||||
we received a badly formed packet - log it
|
||||
*/
|
||||
void nbtd_bad_packet(struct nbt_name_packet *packet,
|
||||
const struct socket_address *src, const char *reason)
|
||||
{
|
||||
DEBUG(2,("nbtd: bad packet '%s' from %s:%d\n", reason, src->addr, src->port));
|
||||
if (DEBUGLVL(5)) {
|
||||
NDR_PRINT_DEBUG(nbt_name_packet, packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
see if an incoming packet is a broadcast packet from one of our own
|
||||
interfaces
|
||||
*/
|
||||
BOOL nbtd_self_packet_and_bcast(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *packet,
|
||||
const struct socket_address *src)
|
||||
{
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
|
||||
/* if its not a broadcast then its not considered a self packet */
|
||||
if (!(packet->operation & NBT_FLAG_BROADCAST)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
/*
|
||||
* this uses the fact that iface->nbtsock is the unicast listen address
|
||||
* if the interface isn't the global bcast interface
|
||||
*
|
||||
* so if the request was directed to the unicast address it isn't a broadcast
|
||||
* message
|
||||
*/
|
||||
if (iface->nbtsock == nbtsock &&
|
||||
iface != iface->nbtsrv->bcast_interface) {
|
||||
return False;
|
||||
}
|
||||
|
||||
return nbtd_self_packet(nbtsock, packet, src);
|
||||
}
|
||||
|
||||
BOOL nbtd_self_packet(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *packet,
|
||||
const struct socket_address *src)
|
||||
{
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
struct nbtd_server *nbtsrv = iface->nbtsrv;
|
||||
|
||||
/* if its not from the nbt port, then it wasn't a broadcast from us */
|
||||
if (src->port != lp_nbt_port()) {
|
||||
return False;
|
||||
}
|
||||
|
||||
/* we have to loop over our interface list, seeing if its from
|
||||
one of our own interfaces */
|
||||
for (iface=nbtsrv->interfaces;iface;iface=iface->next) {
|
||||
if (strcmp(src->addr, iface->ip_address) == 0) {
|
||||
return True;
|
||||
}
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
send a name query reply
|
||||
*/
|
||||
void nbtd_name_query_reply(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *request_packet,
|
||||
struct socket_address *src,
|
||||
struct nbt_name *name, uint32_t ttl,
|
||||
uint16_t nb_flags, const char **addresses)
|
||||
{
|
||||
struct nbt_name_packet *packet;
|
||||
size_t num_addresses = str_list_length(addresses);
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
struct nbtd_server *nbtsrv = iface->nbtsrv;
|
||||
int i;
|
||||
|
||||
if (num_addresses == 0) {
|
||||
DEBUG(3,("No addresses in name query reply - failing\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
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_QUERY |
|
||||
NBT_FLAG_AUTHORITIVE |
|
||||
NBT_FLAG_RECURSION_DESIRED |
|
||||
NBT_FLAG_RECURSION_AVAIL;
|
||||
|
||||
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 = ttl;
|
||||
packet->answers[0].rdata.netbios.length = num_addresses*6;
|
||||
packet->answers[0].rdata.netbios.addresses =
|
||||
talloc_array(packet->answers, struct nbt_rdata_address, num_addresses);
|
||||
if (packet->answers[0].rdata.netbios.addresses == NULL) goto failed;
|
||||
|
||||
for (i=0;i<num_addresses;i++) {
|
||||
struct nbt_rdata_address *addr =
|
||||
&packet->answers[0].rdata.netbios.addresses[i];
|
||||
addr->nb_flags = nb_flags;
|
||||
addr->ipaddr = talloc_strdup(packet->answers, addresses[i]);
|
||||
if (addr->ipaddr == NULL) goto failed;
|
||||
}
|
||||
|
||||
DEBUG(7,("Sending name query reply for %s at %s to %s:%d\n",
|
||||
nbt_name_string(packet, name), addresses[0], src->addr, src->port));
|
||||
|
||||
nbtsrv->stats.total_sent++;
|
||||
nbt_name_reply_send(nbtsock, src, packet);
|
||||
|
||||
failed:
|
||||
talloc_free(packet);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
send a negative name query reply
|
||||
*/
|
||||
void nbtd_negative_name_query_reply(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *request_packet,
|
||||
struct socket_address *src)
|
||||
{
|
||||
struct nbt_name_packet *packet;
|
||||
struct nbt_name *name = &request_packet->questions[0].name;
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
struct nbtd_server *nbtsrv = iface->nbtsrv;
|
||||
|
||||
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_QUERY |
|
||||
NBT_FLAG_AUTHORITIVE |
|
||||
NBT_RCODE_NAM;
|
||||
|
||||
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_NULL;
|
||||
packet->answers[0].rr_class = NBT_QCLASS_IP;
|
||||
packet->answers[0].ttl = 0;
|
||||
ZERO_STRUCT(packet->answers[0].rdata);
|
||||
|
||||
DEBUG(7,("Sending negative name query reply for %s to %s:%d\n",
|
||||
nbt_name_string(packet, name), src->addr, src->port));
|
||||
|
||||
nbtsrv->stats.total_sent++;
|
||||
nbt_name_reply_send(nbtsock, src, packet);
|
||||
|
||||
failed:
|
||||
talloc_free(packet);
|
||||
}
|
||||
|
||||
/*
|
||||
send a name registration reply
|
||||
*/
|
||||
void nbtd_name_registration_reply(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *request_packet,
|
||||
struct socket_address *src,
|
||||
uint8_t rcode)
|
||||
{
|
||||
struct nbt_name_packet *packet;
|
||||
struct nbt_name *name = &request_packet->questions[0].name;
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
struct nbtd_server *nbtsrv = iface->nbtsrv;
|
||||
|
||||
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_REGISTER |
|
||||
NBT_FLAG_AUTHORITIVE |
|
||||
NBT_FLAG_RECURSION_DESIRED |
|
||||
NBT_FLAG_RECURSION_AVAIL |
|
||||
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 registration reply for %s to %s:%d\n",
|
||||
rcode==0?"positive":"negative",
|
||||
nbt_name_string(packet, name), src->addr, src->port));
|
||||
|
||||
nbtsrv->stats.total_sent++;
|
||||
nbt_name_reply_send(nbtsock, src, 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,
|
||||
struct socket_address *src,
|
||||
uint8_t rcode)
|
||||
{
|
||||
struct nbt_name_packet *packet;
|
||||
struct nbt_name *name = &request_packet->questions[0].name;
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
struct nbtd_server *nbtsrv = iface->nbtsrv;
|
||||
|
||||
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->addr, src->port));
|
||||
|
||||
nbtsrv->stats.total_sent++;
|
||||
nbt_name_reply_send(nbtsock, src, packet);
|
||||
|
||||
failed:
|
||||
talloc_free(packet);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
send a WACK reply
|
||||
*/
|
||||
void nbtd_wack_reply(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *request_packet,
|
||||
struct socket_address *src,
|
||||
uint32_t ttl)
|
||||
{
|
||||
struct nbt_name_packet *packet;
|
||||
struct nbt_name *name = &request_packet->questions[0].name;
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
struct nbtd_server *nbtsrv = iface->nbtsrv;
|
||||
|
||||
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_WACK |
|
||||
NBT_FLAG_AUTHORITIVE;
|
||||
|
||||
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 = ttl;
|
||||
packet->answers[0].rdata.data.length = 2;
|
||||
packet->answers[0].rdata.data.data = talloc_size(packet, 2);
|
||||
if (packet->answers[0].rdata.data.data == NULL) goto failed;
|
||||
RSSVAL(packet->answers[0].rdata.data.data, 0, request_packet->operation);
|
||||
|
||||
DEBUG(7,("Sending WACK reply for %s to %s:%d\n",
|
||||
nbt_name_string(packet, name), src->addr, src->port));
|
||||
|
||||
nbtsrv->stats.total_sent++;
|
||||
nbt_name_reply_send(nbtsock, src, packet);
|
||||
|
||||
failed:
|
||||
talloc_free(packet);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
answer name queries
|
||||
|
||||
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/util/dlinklist.h"
|
||||
#include "system/network.h"
|
||||
#include "nbt_server/nbt_server.h"
|
||||
#include "nbt_server/wins/winsserver.h"
|
||||
#include "librpc/gen_ndr/ndr_nbt.h"
|
||||
#include "lib/socket/socket.h"
|
||||
|
||||
/*
|
||||
answer a name query
|
||||
*/
|
||||
void nbtd_request_query(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *packet,
|
||||
struct socket_address *src)
|
||||
{
|
||||
struct nbtd_iface_name *iname;
|
||||
struct nbt_name *name;
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
|
||||
/* see if its a node status query */
|
||||
if (packet->qdcount == 1 &&
|
||||
packet->questions[0].question_type == NBT_QTYPE_STATUS) {
|
||||
nbtd_query_status(nbtsock, packet, src);
|
||||
return;
|
||||
}
|
||||
|
||||
NBTD_ASSERT_PACKET(packet, src, packet->qdcount == 1);
|
||||
NBTD_ASSERT_PACKET(packet, src,
|
||||
packet->questions[0].question_type == NBT_QTYPE_NETBIOS);
|
||||
NBTD_ASSERT_PACKET(packet, src,
|
||||
packet->questions[0].question_class == NBT_QCLASS_IP);
|
||||
|
||||
/* see if we have the requested name on this interface */
|
||||
name = &packet->questions[0].name;
|
||||
|
||||
iname = nbtd_find_iname(iface, name, 0);
|
||||
if (iname == NULL) {
|
||||
/* don't send negative replies to broadcast queries */
|
||||
if (packet->operation & NBT_FLAG_BROADCAST) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet->operation & NBT_FLAG_RECURSION_DESIRED) {
|
||||
nbtd_winsserver_request(nbtsock, packet, src);
|
||||
return;
|
||||
}
|
||||
|
||||
/* otherwise send a negative reply */
|
||||
nbtd_negative_name_query_reply(nbtsock, packet, src);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* normally we should forward all queries with the
|
||||
* recursion desired flag to the wins server, but this
|
||||
* breaks are winsclient code, when doing mhomed registrations
|
||||
*/
|
||||
if (!(packet->operation & NBT_FLAG_BROADCAST) &&
|
||||
(packet->operation & NBT_FLAG_RECURSION_DESIRED) &&
|
||||
(iname->nb_flags & NBT_NM_GROUP) &&
|
||||
lp_wins_support()) {
|
||||
nbtd_winsserver_request(nbtsock, packet, src);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if the name is not yet active and its a broadcast query then
|
||||
ignore it for now */
|
||||
if (!(iname->nb_flags & NBT_NM_ACTIVE) &&
|
||||
(packet->operation & NBT_FLAG_BROADCAST)) {
|
||||
DEBUG(7,("Query for %s from %s - name not active yet on %s\n",
|
||||
nbt_name_string(packet, name), src->addr, iface->ip_address));
|
||||
return;
|
||||
}
|
||||
|
||||
nbtd_name_query_reply(nbtsock, packet, src,
|
||||
&iname->name, iname->ttl, iname->nb_flags,
|
||||
nbtd_address_list(iface, packet));
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
register our names
|
||||
|
||||
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 "lib/util/dlinklist.h"
|
||||
#include "nbt_server/nbt_server.h"
|
||||
#include "smbd/service_task.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "librpc/gen_ndr/ndr_samr.h"
|
||||
#include "nbt_server/wins/winsserver.h"
|
||||
#include "librpc/gen_ndr/ndr_nbt.h"
|
||||
|
||||
|
||||
static void nbtd_start_refresh_timer(struct nbtd_iface_name *iname);
|
||||
|
||||
/*
|
||||
a name refresh request has completed
|
||||
*/
|
||||
static void refresh_completion_handler(struct nbt_name_request *req)
|
||||
{
|
||||
struct nbtd_iface_name *iname = talloc_get_type(req->async.private,
|
||||
struct nbtd_iface_name);
|
||||
NTSTATUS status;
|
||||
struct nbt_name_refresh io;
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(iname);
|
||||
|
||||
status = nbt_name_refresh_recv(req, tmp_ctx, &io);
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
|
||||
DEBUG(4,("Refreshed name %s with %s on interface %s\n",
|
||||
nbt_name_string(tmp_ctx, &iname->name),
|
||||
iname->iface->ip_address, iname->iface->bcast_address));
|
||||
iname->registration_time = timeval_current();
|
||||
nbtd_start_refresh_timer(iname);
|
||||
talloc_free(tmp_ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
iname->nb_flags |= NBT_NM_CONFLICT;
|
||||
iname->nb_flags &= ~NBT_NM_ACTIVE;
|
||||
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1,("Name conflict from %s refreshing name %s with %s on interface %s - %s\n",
|
||||
io.out.reply_addr, nbt_name_string(tmp_ctx, &iname->name),
|
||||
iname->iface->ip_address, iname->iface->bcast_address,
|
||||
nt_errstr(nbt_rcode_to_ntstatus(io.out.rcode))));
|
||||
} else {
|
||||
DEBUG(1,("Error refreshing name %s with %s on interface %s - %s\n",
|
||||
nbt_name_string(tmp_ctx, &iname->name),
|
||||
iname->iface->ip_address, iname->iface->bcast_address,
|
||||
nt_errstr(status)));
|
||||
}
|
||||
|
||||
talloc_free(tmp_ctx);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
handle name refresh timer events
|
||||
*/
|
||||
static void name_refresh_handler(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_register io;
|
||||
struct nbt_name_request *req;
|
||||
struct nbtd_server *nbtsrv = iface->nbtsrv;
|
||||
|
||||
/* setup a single name register request. Notice that we don't
|
||||
use a name refresh request, as Windows and Samba3 do not
|
||||
defend against broadcast name refresh packets. So for this
|
||||
to be of any use at all, we need to refresh using name
|
||||
registration packets */
|
||||
io.in.name = iname->name;
|
||||
io.in.dest_addr = iface->bcast_address;
|
||||
io.in.address = iface->ip_address;
|
||||
io.in.nb_flags = iname->nb_flags;
|
||||
io.in.ttl = iname->ttl;
|
||||
io.in.register_demand = False;
|
||||
io.in.broadcast = True;
|
||||
io.in.multi_homed = False;
|
||||
io.in.timeout = 3;
|
||||
io.in.retries = 0;
|
||||
|
||||
nbtsrv->stats.total_sent++;
|
||||
req = nbt_name_register_send(iface->nbtsock, &io);
|
||||
if (req == NULL) return;
|
||||
|
||||
req->async.fn = refresh_completion_handler;
|
||||
req->async.private = iname;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
start a timer to refresh this name
|
||||
*/
|
||||
static void nbtd_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),
|
||||
name_refresh_handler, iname);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
a name registration has completed
|
||||
*/
|
||||
static void nbtd_register_handler(struct composite_context *creq)
|
||||
{
|
||||
struct nbtd_iface_name *iname = talloc_get_type(creq->async.private_data,
|
||||
struct nbtd_iface_name);
|
||||
NTSTATUS status;
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(iname);
|
||||
|
||||
status = nbt_name_register_bcast_recv(creq);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
/* good - nobody complained about our registration */
|
||||
iname->nb_flags |= NBT_NM_ACTIVE;
|
||||
DEBUG(3,("Registered %s with %s on interface %s\n",
|
||||
nbt_name_string(tmp_ctx, &iname->name),
|
||||
iname->iface->ip_address, iname->iface->bcast_address));
|
||||
iname->registration_time = timeval_current();
|
||||
talloc_free(tmp_ctx);
|
||||
nbtd_start_refresh_timer(iname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* someone must have replied with an objection! */
|
||||
iname->nb_flags |= NBT_NM_CONFLICT;
|
||||
|
||||
DEBUG(1,("Error registering %s with %s on interface %s - %s\n",
|
||||
nbt_name_string(tmp_ctx, &iname->name),
|
||||
iname->iface->ip_address, iname->iface->bcast_address,
|
||||
nt_errstr(status)));
|
||||
talloc_free(tmp_ctx);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
register a name on a network interface
|
||||
*/
|
||||
static void nbtd_register_name_iface(struct nbtd_interface *iface,
|
||||
const char *name, enum nbt_name_type type,
|
||||
uint16_t nb_flags)
|
||||
{
|
||||
struct nbtd_iface_name *iname;
|
||||
const char *scope = lp_netbios_scope();
|
||||
struct nbt_name_register_bcast io;
|
||||
struct composite_context *creq;
|
||||
struct nbtd_server *nbtsrv = iface->nbtsrv;
|
||||
|
||||
iname = talloc(iface, struct nbtd_iface_name);
|
||||
if (!iname) return;
|
||||
|
||||
iname->iface = iface;
|
||||
iname->name.name = strupper_talloc(iname, name);
|
||||
iname->name.type = type;
|
||||
if (scope && *scope) {
|
||||
iname->name.scope = strupper_talloc(iname, scope);
|
||||
} else {
|
||||
iname->name.scope = NULL;
|
||||
}
|
||||
iname->nb_flags = nb_flags;
|
||||
iname->ttl = lp_parm_int(-1, "nbtd", "bcast_ttl", 300000);
|
||||
iname->registration_time = timeval_zero();
|
||||
iname->wins_server = NULL;
|
||||
|
||||
DLIST_ADD_END(iface->names, iname, struct nbtd_iface_name *);
|
||||
|
||||
if (nb_flags & NBT_NM_PERMANENT) {
|
||||
/* permanent names are not announced and are immediately active */
|
||||
iname->nb_flags |= NBT_NM_ACTIVE;
|
||||
iname->ttl = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* if this is the wins interface, then we need to do a special
|
||||
wins name registration */
|
||||
if (iface == iface->nbtsrv->wins_interface) {
|
||||
nbtd_winsclient_register(iname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* setup a broadcast name registration request */
|
||||
io.in.name = iname->name;
|
||||
io.in.dest_addr = iface->bcast_address;
|
||||
io.in.address = iface->ip_address;
|
||||
io.in.nb_flags = nb_flags;
|
||||
io.in.ttl = iname->ttl;
|
||||
|
||||
nbtsrv->stats.total_sent++;
|
||||
creq = nbt_name_register_bcast_send(iface->nbtsock, &io);
|
||||
if (creq == NULL) return;
|
||||
|
||||
creq->async.fn = nbtd_register_handler;
|
||||
creq->async.private_data = iname;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
register one name on all our interfaces
|
||||
*/
|
||||
static void nbtd_register_name(struct nbtd_server *nbtsrv,
|
||||
const char *name, enum nbt_name_type type,
|
||||
uint16_t nb_flags)
|
||||
{
|
||||
struct nbtd_interface *iface;
|
||||
|
||||
/* register with all the local interfaces */
|
||||
for (iface=nbtsrv->interfaces;iface;iface=iface->next) {
|
||||
nbtd_register_name_iface(iface, name, type, nb_flags);
|
||||
}
|
||||
|
||||
/* register on our general broadcast interface as a permanent name */
|
||||
if (nbtsrv->bcast_interface) {
|
||||
nbtd_register_name_iface(nbtsrv->bcast_interface, name, type,
|
||||
nb_flags | NBT_NM_PERMANENT);
|
||||
}
|
||||
|
||||
/* register with our WINS servers */
|
||||
if (nbtsrv->wins_interface) {
|
||||
nbtd_register_name_iface(nbtsrv->wins_interface, name, type, nb_flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
register our names on all interfaces
|
||||
*/
|
||||
void nbtd_register_names(struct nbtd_server *nbtsrv)
|
||||
{
|
||||
uint16_t nb_flags = NBT_NODE_M;
|
||||
const char **aliases;
|
||||
|
||||
/* note that we don't initially mark the names "ACTIVE". They are
|
||||
marked active once registration is successful */
|
||||
nbtd_register_name(nbtsrv, lp_netbios_name(), NBT_NAME_CLIENT, nb_flags);
|
||||
nbtd_register_name(nbtsrv, lp_netbios_name(), NBT_NAME_USER, nb_flags);
|
||||
nbtd_register_name(nbtsrv, lp_netbios_name(), NBT_NAME_SERVER, nb_flags);
|
||||
|
||||
aliases = lp_netbios_aliases();
|
||||
while (aliases && aliases[0]) {
|
||||
nbtd_register_name(nbtsrv, aliases[0], NBT_NAME_CLIENT, nb_flags);
|
||||
nbtd_register_name(nbtsrv, aliases[0], NBT_NAME_SERVER, nb_flags);
|
||||
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 | NBT_NM_GROUP);
|
||||
break;
|
||||
case ROLE_DOMAIN_BDC:
|
||||
nbtd_register_name(nbtsrv, lp_workgroup(), NBT_NAME_LOGON, nb_flags | NBT_NM_GROUP);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
nb_flags |= NBT_NM_GROUP;
|
||||
nbtd_register_name(nbtsrv, lp_workgroup(), NBT_NAME_CLIENT, nb_flags);
|
||||
|
||||
nb_flags |= NBT_NM_PERMANENT;
|
||||
nbtd_register_name(nbtsrv, "__SAMBA__", NBT_NAME_CLIENT, nb_flags);
|
||||
nbtd_register_name(nbtsrv, "__SAMBA__", NBT_NAME_SERVER, nb_flags);
|
||||
nbtd_register_name(nbtsrv, "*", NBT_NAME_CLIENT, nb_flags);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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"
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user