1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

tidied up: code shuffling and documentation.

created namedb*.c nameservresp.c nameservreply.c and namepacket.c
added modules to Makefile, downloading dan's current version first :-)
shuffled docs to match source
created more docs

fixed bug in announce_backup() discovered when going nameannounce.doc:
backup list requests to the master browser should be used when samba is
not a master browser; backup list requests to the primary domain
controller should be used when samba is not a primary domain controller.

fixed bug in sync_server: it would never send MasterAnnounce packets.

removed the code that ignored special browser names: these should only
be ignored (except 0x1b names) when broadcasted name queries are sent,
not when directed registration or directed queries are sent samba as a
WINS server. (note: exactly what's going on is still uncertain).

renamed NAME_QUERY_MST_SRV_CHK  to NAME_QUERY_PDC_SRV_CHK  (more accurate).
renamed NAME_STATUS_MST_SRV_CHK to NAME_STATUS_PDC_SRV_CHK (more accurate).

added secured WINS name registration: a new 'state' NAME_REGISTER_CHALLENGE;
functions send_name_response(), response_name_query_register(); added
sending of WAIT ACKNOWLEDGEMENT packet; added a reply_to_ip field to
the response record structure so that after the name query challenge,
you know who to inform of the outcome of that challenge.

note: these are all currently untested modifications (yikes!)

lkcl
(This used to be commit b50ff657dd)
This commit is contained in:
Samba Release Account 1996-07-07 12:36:18 +00:00
parent 4d314a96e7
commit b338bce94f
20 changed files with 1361 additions and 2765 deletions

View File

@ -20,6 +20,8 @@
*/
#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
/* NTAS uses 2, NT uses 1, WfWg uses 0 */
#define MAINTAIN_LIST 2
#define ELECTION_VERSION 1
@ -33,9 +35,13 @@
#define NMB_REG 0x05 /* see rfc1002.txt 4.2.2,3,5,6,7,8 */
#define NMB_REG_REFRESH 0x09 /* see rfc1002.txt 4.2.4 */
#define NMB_REL 0x06 /* see rfc1002.txt 4.2.9,10,11 */
#define NMB_WAIT_ACK 0x07 /* see rfc1002.txt 4.2.17 */
#define NMB_WAIT_ACK 0x07 /* see rfc1002.txt 4.2.16 */
/* XXXX what about all the other types?? 0x1, 0x2, 0x3, 0x4, 0x8? */
#define FIND_SELF 0x01
#define FIND_WINS 0x02
#define FIND_LOCAL 0x04
/* NetBIOS flags */
#define NB_GROUP 0x80
#define NB_PERM 0x02
@ -83,13 +89,14 @@ enum master_state { MST_NONE, MST_WON, MST_MSB, MST_BROWSER, MST_DOMAIN };
enum state_type
{
NAME_STATUS_MASTER_CHECK,
NAME_STATUS_CHECK,
NAME_STATUS_PDC_SRV_CHK,
NAME_STATUS_SRV_CHK,
NAME_REGISTER_CHALLENGE,
NAME_REGISTER,
NAME_RELEASE,
NAME_QUERY_CONFIRM,
NAME_QUERY_SYNC,
NAME_QUERY_MST_SRV_CHK,
NAME_QUERY_PDC_SRV_CHK,
NAME_QUERY_SRV_CHK,
NAME_QUERY_FIND_MST,
NAME_QUERY_MST_CHK
@ -189,7 +196,8 @@ struct response_record
BOOL bcast;
BOOL recurse;
struct in_addr to_ip;
struct in_addr send_ip;
struct in_addr reply_to_ip;
int num_msgs;

View File

@ -70,12 +70,16 @@ void announce_request(struct work_record *work, struct in_addr ip)
CVAL(p,0) = ANN_AnnouncementRequest;
p++;
CVAL(p,0) = work->token; /* flags?? XXXX probably a token*/
CVAL(p,0) = work->token; /* (local) unique workgroup token id */
p++;
StrnCpy(p,myname,16);
strupper(p);
p = skip_string(p,1);
/* XXXX note: if we sent the announcement request to 0x1d instead
of 0x1e, then we could get the master browser to announce to
us instead of the members of the workgroup. wha-hey! */
send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
}
@ -118,17 +122,21 @@ void sync_server(enum state_type state, char *serv_name, char *work_name,
{
add_browser_entry(serv_name, name_type, work_name, 0, ip);
if (state == NAME_QUERY_MST_SRV_CHK)
{
/* announce ourselves as a master browser to serv_name */
do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
if (state == NAME_STATUS_PDC_SRV_CHK)
{
/* announce ourselves as a master browser to serv_name */
do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
0x20, 0, ip);
}
}
}
/****************************************************************************
construct a host announcement unicast
this function should not be used heavily, and only when we are _not_
a master browser and _not_ a primary domain controller.
**************************************************************************/
void announce_backup(void)
{
@ -158,18 +166,11 @@ void announce_backup(void)
if (!work) continue;
if (AM_MASTER(work) && AM_DOMCTL(work)) continue;
/* found one: announce it across all domains */
for (d = subnetlist; d; d = d->next)
{
int type=0;
if (AM_DOMCTL(work)) {
type = 0x1b;
} else if (AM_MASTER(work)) {
type = 0x1d;
} else {
continue;
}
DEBUG(2,("sending announce backup %s workgroup %s(%d)\n",
inet_ntoa(d->bcast_ip),work->work_group,
@ -185,12 +186,31 @@ void announce_backup(void)
p += 5;
p++;
send_mailslot_reply(BROWSE_MAILSLOT,
if (!AM_DOMCTL(work))
{
/* only ask for a list of backup domain controllers
if we are not a domain controller ourselves */
send_mailslot_reply(BROWSE_MAILSLOT,
ClientDGRAM,outbuf,
PTR_DIFF(p,outbuf),
myname, work->work_group,
0x0,type,d->bcast_ip,
0x0,0x1b,d->bcast_ip,
*iface_ip(d->bcast_ip));
}
if (!AM_MASTER(work))
{
/* only ask for a list of master browsers if we
are not a master browser ourselves */
send_mailslot_reply(BROWSE_MAILSLOT,
ClientDGRAM,outbuf,
PTR_DIFF(p,outbuf),
myname, work->work_group,
0x0,0x1b,d->bcast_ip,
*iface_ip(d->bcast_ip));
}
}
}
}
@ -222,12 +242,12 @@ static void do_announce_host(int command,
StrnCpy(p+5,server_name,16);
strupper(p+5);
CVAL(p,21) = 2; /* major version */
CVAL(p,22) = 2; /* minor version */
CVAL(p,21) = 0x02; /* major version */
CVAL(p,22) = 0x02; /* minor version */
SIVAL(p,23,server_type);
SSVAL(p,27,0xaa55); /* browse signature */
SSVAL(p,29,1); /* browse version */
SSVAL(p,29,0x001f); /* browse version: CIFS draft 1.0 indicates 0x001f */
strcpy(p+31,server_comment);
p += 31;
@ -242,6 +262,28 @@ static void do_announce_host(int command,
}
/****************************************************************************
remove all samba's server entries
****************************************************************************/
void remove_my_servers(void)
{
struct subnet_record *d;
for (d = subnetlist; d; d = d->next)
{
struct work_record *work;
for (work = d->workgrouplist; work; work = work->next)
{
struct server_record *s;
for (s = work->serverlist; s; s = s->next)
{
if (!strequal(myname,s->serv.name)) continue;
announce_server(d, work, s->serv.name, s->serv.comment, 0, 0);
}
}
}
}
/****************************************************************************
announce a server entry
****************************************************************************/
@ -309,6 +351,11 @@ void announce_host(void)
struct server_record *s;
BOOL announce = False;
/* must work on the code that does announcements at up to
30 seconds later if a master browser sends us a request
announce.
*/
if (work->needannounce) {
/* drop back to a max 3 minute announce - this is to prevent a
single lost packet from stuffing things up for too long */
@ -364,7 +411,7 @@ void announce_host(void)
least 15 minutes.
this actually gets done in search_and_sync_workgroups() via the
NAME_QUERY_MST_SRV_CHK command, if there is a response from the
NAME_QUERY_PDC_SRV_CHK command, if there is a response from the
name query initiated here. see response_name_query()
**************************************************************************/
void announce_master(void)
@ -419,9 +466,9 @@ void announce_master(void)
ip = ipzero;
queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
NAME_QUERY_MST_SRV_CHK,
NAME_QUERY_PDC_SRV_CHK,
work->work_group,0x1b,0,0,
False, False, ip);
False, False, ip, ip);
}
else
{
@ -429,9 +476,9 @@ void announce_master(void)
for (d2 = subnetlist; d2; d2 = d2->next)
{
queue_netbios_packet(d,ClientNMB,NMB_QUERY,
NAME_QUERY_MST_SRV_CHK,
NAME_QUERY_PDC_SRV_CHK,
work->work_group,0x1b,0,0,
True, False, d2->bcast_ip);
True, False, d2->bcast_ip, d2->bcast_ip);
}
}
}
@ -463,9 +510,9 @@ void announce_master(void)
/* check the existence of a pdc for this workgroup, and if
one exists at the specified ip, sync with it and announce
ourselves as a master browser to it */
queue_netbios_pkt_wins(d,ClientNMB, NMB_QUERY,NAME_QUERY_MST_SRV_CHK,
queue_netbios_pkt_wins(d,ClientNMB, NMB_QUERY,NAME_QUERY_PDC_SRV_CHK,
work->work_group,0x1b, 0, 0,
bcast, False, ip);
bcast, False, ip, ip);
}
}
}

137
source3/nameannounce.doc Normal file
View File

@ -0,0 +1,137 @@
this module deals with announcements: the sending of announcement requests
and the sending of announcements either to refresh other servers' records
or as a response to announcement requests.
/*************************************************************************
announce_master()
*************************************************************************/
this function is responsible for announcing samba as a master browser
to all known primary domain controllers.
this announcement is sent out at CHECK_TIME_MST_ANNOUNCE minute
intervals, only if samba is a master browser on one or more of
its local interfaces.
if no domain controller has been specified (lp_domain_controller())
samba goes through its list of servers looking for primary domain
controllers. when it finds one (other than itself) it will either
initiate a NAME_QUERY_PDC_SRV_CHK by broadcast or with a WINS
server. this will result in a NAME_STATUS_PDC_SRV_CHK, which
will result in a sync browse list and an announcement
ANN_MasterAnnounce being sent (see sync_server()).
if a domain controller has been specified, samba will search for
a primary domain controller for its workgroup (either by directed
packet or by broadcast if it cannot resolve the domain controller
name using DNS), which results in the same action as listed above.
/*************************************************************************
announce_host()
*************************************************************************/
this complex-looking function is responsible for announcing samba's
existence to other servers by broadcast. the actual announcement
is carried out by announce_server().
the time period between samba's announcement will stretch from one
minute to twelve minutes by one minute. if samba has received an
announce request from a master browser, then it should answer at
any random interval between zero and thirty seconds after the
request is received. this is to ensure that the master browser
does not get overloaded with responses!
/*************************************************************************
announce_server()
*************************************************************************/
this function is responsible for sending announcement packets.
these packets are received by other servers, which will then
update their records accordingly: what services we have, our
name, our comment field and our time to live (to name a few).
if we are a master browser, then using do_announce_host() we
must send an announcement notifying members of that workgroup
that we are their master browser, and another announcement
indicating to all backup browsers and master browsers that
we are a master browser.
(note: if another master browser receives this announcement
and thinks that it is also the master browser for this
workgroup, it stops being a master browser and forces an
election).
if we are not a master browser, then we send an announcement
notifying the master browser that we are a member of its
workgroup.
/*************************************************************************
remove_my_servers()
*************************************************************************/
this function is responsible for informing other servers that
samba is about to go down. it announces, on all subnets, that
samba's time to live is zero and that it has no services.
/*************************************************************************
do_announce_host()
*************************************************************************/
this function is responsible for sending out an announcement
MAILSLOT browse packet. it contains information such as the
time to live, name of the server, services that the server
offers etc.
the format of this MAILSLOT browse packet is described in
draft-heizer-cifs-v1-spec-00.txt 3.9.50.4.1 page 165-6.
/*************************************************************************
announce_backup()
*************************************************************************/
this function is responsible for getting master browsers and domain
controllers to send us lists of backup servers. this is done by
sending an ANN_GetBackupListReq browse mailslot.
the master browser, or primary domain controller, should respond
with an ANN_GetBackupListResp browse mailslot containing the list
of backup servers.
/*************************************************************************
sync_server()
*************************************************************************/
this function is responsible for initiating a sync browse list
sequence and, if necessary, carrying out an ANN_MasterAnnouncement
to the primary domain controller (that we are also sync'ing
browse lists with).
see nameservresp.c:response_name_status_check().
/*************************************************************************
announce_request()
*************************************************************************/
this function is responsible for sending an announcement request to
another server. this server should respond with an announcement.
if the announce request is sent to WORKGROUP(0x1e) then members of
the workgroup will respond (with ANN_HostAnnounce packets)
if the announce request is sent to WORKGROUP(0x1d) then the master
browser of the workgroup should respond (ANN_LocalMasterAnnounce).
this is untested.
if the announce request is sent to ^1^2__MSBROWSE__^2(0x1) then
(and this is pure speculation), all backup browsers and master
browsers should respond with ANN_DomainAnnounce packets.
this is untested.

View File

@ -178,7 +178,7 @@ static void start_sync_browse_entry(struct browse_cache_record *b)
/* see response_netbios_packet() or expire_netbios_response_entries() */
queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_SYNC,
b->group,0x20,0,0,
False,False,b->ip);
False,False,b->ip,b->ip);
}
b->synced = True;

69
source3/namebrowse.doc Normal file
View File

@ -0,0 +1,69 @@
this module deals with queueing servers that samba must sync browse
lists with. it will always issue a name query immediately before
actually carrying out the NetServerEnum call, to ensure that time
is not wasted by a remote server's failure.
this module was created to minimise the amount of NetServerEnum calls
that samba may be asked to perform, by maintaining the name of a server
for up to a minute after the NetServerEnum call was issued, and
disallowing further NetServerEnum calls to this remote server until
the entry is removed.
samba can ask for a NetServerEnum call to be issued to grab a remote
server's list of servers and workgroups either in its capacity as
a primary domain controller (domain master browser), as a local
master browser.
samba does not deal with becoming a backup master browser properly
at present.
/*************************************************************************
do_browser_lists()
*************************************************************************/
this function is responsible for finding an appropriate entry in the
sync browser cache, initiating a name query (which results in a
NetServerEnum call if there is a positive response), and then
removing all entries that have been actioned and have been around
for over a minute.
/*************************************************************************
start_sync_browse_entry()
*************************************************************************/
this function is responsible for initiating a name query. if a
positive response is received, then this will result in a
NetServerEnum api call.
samba will only initiate this process if it is a master browser
for this workgroup.
/*************************************************************************
add_browser_entry()
*************************************************************************/
this function is responsible for adding a browser into the list of
servers to sync browse lists with. if the server entry has already
been added and syncing browse lists has already been initiated, it
will not be added again.
/*************************************************************************
expire_browse_cache()
*************************************************************************/
this function is responsible for removing entries that have had the
sync browse list initiated (whether that succeeded or not is beyond
this function's scope) and have been in the cache for a while.
/*************************************************************************
add_browse_entry()
*************************************************************************/
this function is responsible for adding a new entry into the list
of servers to sync browse lists with at some point in the near future.

155
source3/namedbname.doc Normal file
View File

@ -0,0 +1,155 @@
this module deals with the NetBIOS name database for samba. it deals
directly with adding, removing, finding, loading and saving of names.
/*************************************************************************
search_for_name()
*************************************************************************/
this function is responsible for finding a name in the appropriate part
of samba's NetBIOS name database. if the name cannot be found, then it
should look the name up using DNS. later modifications will be to
forward the request on to another WINS server, should samba not be able
to find out about the requested name (this will be implemented through
issuing a new type of samba 'state').
the name is first searched for in the NetBIOS cache. if it cannot be
found, then it if the name looks like it's a server-type name (0x20
0x0 or 0x1b) then DNS is used to look for the name.
if DNS fails, then a record of this failure is kept. if it succeeds, then
a new NetBIOS entry is added.
the successfully found name is returned. on failure, NULL is returned.
/*************************************************************************
expire_names()
*************************************************************************/
this function is responsible for removing old NetBIOS names from its
database. no further action is required.
for over-zealous WINS systems, the use of query_refresh_names() is
recommended. this function initiates polling of hosts that have
registered with samba in its capacity as a WINS server. an alternative
means to achieve the same end as query_refresh_names() is to
reduce the time to live when the name is registered with samba,
except that in this instance the responsibility for refreshing the
name is with the owner of the name, not the server with which the name
is registered.
/*************************************************************************
add_netbios_entry()
*************************************************************************/
this function is responsible for adding or updating a NetBIOS name
in the database. into the local interface records, the only names
that will be added are those of primary domain controllers and
samba's own names. into the WINS records, all names are added.
the name to be added / updated will be looked up in the records.
if it is found, then we will not overwrite the entry if the flag
'newonly' is True, or if the name is being added as a non-SELF
(non-samba) name and the records indicate that samba owns the
name.
otherwise, the name is added or updated with the new details.
/*************************************************************************
remove_netbios_entry()
*************************************************************************/
this function is responsible for removing a NetBIOS entry from
the database. the name is searched for in the records using
find_name_search(). if the ip is zero, then the ip is ignored.
the name is removed if the expected source (e.g SELF, REGISTER)
matches that in the database.
/*************************************************************************
load_netbios_names()
*************************************************************************/
this function is responsible for loading any NetBIOS names that samba,
in its WINS capacity, has written out to disk. all the relevant details
are recorded in this file, including the time-to-live. should the
time left to live be small, the name is not added back in to samba's
WINS database.
/*************************************************************************
dump_names()
*************************************************************************/
this function is responsible for outputting NetBIOS names in two formats.
firstly, as debugging information, and secondly, all names that have been
registered with samba in its capacity as a WINS server are written to
disk.
writing all WINS names allows two things. firstly, if samba's NetBIOS
daemon dies or is terminated, on restarting the daemon most if not all
of the registered WINS names will be preserved (which is a good reason
why query_netbios_names() should be used).
/*************************************************************************
find_name_search()
*************************************************************************/
this function is a wrapper around find_name(). find_name_search() can
be told whether to search for the name in a local subnet structure or
in the WINS database. on top of this, it can be told to search only
for samba's SELF names.
if it finds the name in the WINS database, it will set the subnet_record
and also return the name it finds.
/*************************************************************************
find_name()
*************************************************************************/
this function is a low-level search function that searches a single
interface's NetBIOS records for a name. if the ip to be found is
zero then the ip address is ignored. this is to enable a name to
be found without knowing its ip address, and also to find the exact
name if a large number of group names are added with different ip
addresses.
/*************************************************************************
remove_name()
*************************************************************************/
this function is responsible for removing a specific NetBIOS entry
from a subnet list's records. only if the pointer to the entry is
in the list will the name be removed.
/*************************************************************************
add_name()
*************************************************************************/
this function is responsible for adding a NetBIOS entry into a
subnet list's records.
/*************************************************************************
ms_browser_name()
*************************************************************************/
this function returns True if the NetBIOS name passed to it is
^1^2__MSBROWSE__^2^1
/*************************************************************************
name_equal()
*************************************************************************/
this function returns True if the two NetBIOS names passed to it
match in name, type and scope: the NetBIOS names are equal.

48
source3/namedbresp.doc Normal file
View File

@ -0,0 +1,48 @@
module namedbresp deals with the maintenance of the list of expected
responses - creating, finding and removal.
module nameresp deals with the initial transmission, re-transmission
and time-out of netbios response records.
/*************************************************************************
find_response_record()
*************************************************************************/
this function is responsible for matching the unique response transaction
id with an expected response record. as a side-effect of this search,
it will find the subnet (or the WINS pseudo-subnet) that samba expected
the response to come from.
/*************************************************************************
make_response_queue_record()
*************************************************************************/
this function is responsible for creating a response record, which will
be queued awaiting a response.
the number of retries is set to 4, and the retry period set to 1 second.
if no response is received, then the packet is re-transmitted, which is
why so much information is stored in the response record.
the number of expected responses queued is kept, so listen_for_packets()
knows it must time-out after 1 second if one or more responses are
expected.
/*************************************************************************
remove_response_record()
*************************************************************************/
this function is responsible for removing a response record from the
expected response queue. the number of expected responses is decreased.
/*************************************************************************
add_response_record()
*************************************************************************/
this function is responsible for adding the response record created by
make_response_queue_record() into the appropriate response record queue.

View File

@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
NBT netbios routines and daemon - version 2
Copyright (C) Andrew Tridgell 1994-1995
Copyright (C) Andrew Tridgell 1994-1996
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
@ -18,11 +18,17 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Module name: nameelect.c
Revision History:
14 jan 96: lkcl@pires.co.uk
added multiple workgroup domain master support
04 jul 96: lkcl@pires.co.uk
added system to become a master browser by stages.
*/
#include "includes.h"
@ -75,7 +81,7 @@ void check_master_browser(void)
{
queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK,
work->work_group,0x1d,0,0,
True,False,d->bcast_ip);
True,False,d->bcast_ip,d->bcast_ip);
}
}
}
@ -134,7 +140,7 @@ void send_election(struct subnet_record *d, char *group,uint32 criterion,
bzero(outbuf,sizeof(outbuf));
p = outbuf;
CVAL(p,0) = 8; /* election */
CVAL(p,0) = ANN_Election; /* election */
p++;
CVAL(p,0) = (criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION;
@ -166,13 +172,13 @@ void name_unregister_work(struct subnet_record *d, char *name, int name_type)
if (!(work = find_workgroupstruct(d, name, False))) return;
if (special_browser_name(name, name_type) ||
if (ms_browser_name(name, name_type) ||
(AM_MASTER(work) && strequal(name, lp_workgroup()) == 0 &&
(name_type == 0x1d || name_type == 0x1b)))
{
int remove_type = 0;
if (special_browser_name(name, name_type))
if (ms_browser_name(name, name_type))
remove_type = SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER;
if (name_type == 0x1d)
remove_type = SV_TYPE_MASTER_BROWSER;
@ -247,7 +253,7 @@ void become_master(struct subnet_record *d, struct work_record *work)
{
case MST_NONE: /* while we were nothing but a server... */
{
work->state = MST_WON; /* election win was successful */
work->state = MST_WON; /* ... an election win was successful */
work->ElectionCriterion |= 0x5;
@ -264,7 +270,7 @@ void become_master(struct subnet_record *d, struct work_record *work)
}
case MST_WON: /* while nothing had happened except we won an election... */
{
work->state = MST_MSB; /* registering MSBROWSE was successful */
work->state = MST_MSB; /* ... registering MSBROWSE was successful */
/* add server entry on successful registration of MSBROWSE */
add_server_entry(d,work,work->work_group,domain_type,0,myname,True);
@ -276,9 +282,9 @@ void become_master(struct subnet_record *d, struct work_record *work)
break;
}
case MST_MSB: /* while we were still only registered MSBROWSE state */
case MST_MSB: /* while we were still only registered MSBROWSE state... */
{
work->state = MST_BROWSER; /* registering WORKGROUP(1d) was successful */
work->state = MST_BROWSER; /* ... registering WORKGROUP(1d) succeeded */
/* update our server status */
work->ServerType |= SV_TYPE_MASTER_BROWSER;
@ -296,12 +302,16 @@ void become_master(struct subnet_record *d, struct work_record *work)
/* add domain master name */
add_my_name_entry(d,work->work_group,0x1b,NB_ACTIVE );
}
else
{
DEBUG(2,("samba not configured as a domain master: no third stage.\n"));
}
break;
}
case MST_BROWSER: /* while we were still a master browser... */
{
work->state = MST_DOMAIN; /* registering WORKGROUP(1b) was successful */
work->state = MST_DOMAIN; /* ... registering WORKGROUP(1b) succeeded */
/* update our server status */
if (lp_domain_master())
@ -513,6 +523,11 @@ void process_election(struct packet_struct *p,char *buf)
/****************************************************************************
checks whether a browser election is to be run on any workgroup
this function really ought to return the time between election
packets (which depends on whether samba intends to be a domain
master or a master browser) in milliseconds.
***************************************************************************/
BOOL check_elections(void)
{

207
source3/nameelect.doc Normal file
View File

@ -0,0 +1,207 @@
the module nameelect.c deals with initiating, winning, losing
browsing elections, and checking if browsers are still around,
and the consequences of getting involved in all this.
an election packet can be received at any time, which will initiate
an election. samba can also detect that there is no longer a
master browser and will initiate an election.
there is one way to become a master browser, but there are two
ways to un-become a master browser. if you lose an election, you
must stop being a master browser. if you fail to register your
unique special browser names (either on your local subnet or with
the WINS server) then you must stop being a master browser.
this is a double fail-safe mechanism to ensure that there is only
one master browser per workgroup per subnet (and one primary domain
controller - domain master browser - per domain (workgroup) per
wide area network).
(a wide area network is created when one or more servers on a
broadcast-isolated subnet point to the same WINS server).
/*************************************************************************
check_elections()
*************************************************************************/
this function returns True if samba is in the process of running an
election on any of its interfaces. a better version of this function
should return the time-out period in between election packets, in
milliseconds.
/*************************************************************************
process_election()
*************************************************************************/
this function is responsible for dealing with the receipt of an election
browse MAILSLOT packet.
if samba is running an election, it checks the criteria in the packet
received using win_election() to see if it has lost the election or if
it should join in the election.
if it loses the election, then it becomes a non-master.
/*************************************************************************
win_election()
*************************************************************************/
this function returns True if samba has won an election. the criteria
in order of precedence are:
the election version; the election criteria; the time since samba was
started; and as a last resort, a name comparison is used.
/*************************************************************************
run_elections()
*************************************************************************/
this function is responsible for sending out election packets if
samba is running in an election. once the fourth packet is sent
out, it is assumed that we have won, and samba initiates becoming
a master browser.
(it looks like samba sends out an extra packet just to be sure...)
/*************************************************************************
become_nonmaster()
*************************************************************************/
this function is responsible for down-grading samba's status from
either domain master to master browser or nothing, or master browser
to nothing, depending on its current status.
samba can become a non-master in three ways: by losing an election -
see process_election(); by having one of its special browser names
de-registered - see name_unregister_work(); by receiving and
processing a browser reset packet - see process_reset_browser().
when samba stops being a domain master, it must release its unique
0x1b name. when samba stops being a master browser, it must release
its unique 0x1d name.
becoming non-master is done on a per-subnet basis.
/*************************************************************************
become_master()
*************************************************************************/
this function is responsible for slowly turning samba into a
master browser or a domain master (primary domain controller).
this is done in stages. note that this could take a while,
particularly on a broadcast subnet, as we have to wait for
the implicit registration of each name to be accepted.
as each name is successfully registered, become_master() is
called again via name_register_work(), in order to initiate
the next stage (see dead_netbios_entry() - deals with implicit
name registration and response_name_reg() - deals with explicit
registration with a WINS server).
stage 1: was MST_NONE - go to MST_NONE and register ^1^2__MSBROWSE__^2^1.
stage 2: was MST_WON - go to MST_MSB and register WORKGROUP(0x1d)
stage 3: was MST_MSB - go to MST_BROWSER and register WORKGROUP(0x1b)
stage 4: was MST_BROWSER - go to MST_DOMAIN (do not pass GO, do not...)
note that this code still does not cope with the distinction
between different types of nodes, particularly between M and P
nodes (see rfc1001.txt). that will be developed later.
/*************************************************************************
name_register_work()
*************************************************************************/
this function is called when a NetBIOS name is successfully
registered. it will add the registered name into samba's NetBIOS
records.
it has the additional responsibility that when samba is becoming
a master browser, it must initiate the next stage in the progress
towards becoming a master browser.
implicit name registration is done through dead_netbios_entry()
by time-out. explicit name registration is done through
response_name_reg() with a WINS server.
/*************************************************************************
name_unregister_work()
*************************************************************************/
this function is called when there is an objection to a NetBIOS
name being registered. this will always be done through a negative
response to a name registration, whether it be by a host that
already owns the unique name being registered on a subnet, or
by a WINS server.
the name being objected to must be removed from samba's records.
it has the additional responsibility of checking whether samba is
currently a master browser or not, and if so it should initiate
becoming a non-master.
/*************************************************************************
send_election()
*************************************************************************/
this function is responsible for sending a browse mailslot
datagram election packet (of type ANN_Election). it constructs
the packet with all the relevant info needed to participate:
election version; election criteria; time since startup and
our name.
this function can be used to ensure that initiate but lose an
election by specifying a criteria and time up of zero. this
is necessary if we are a master browser and we are about to
go down (politely!) - see nmbd.c:sig_term().
/*************************************************************************
browser_gone()
*************************************************************************/
this function is responsible for dealing with the instance when
the master browser we thought was present on a subnet is no longer
responding.
if it is samba's workgroup, and it's a local interface, samba
detects that it can participate in an election on that interface
and potentially become a master browser or domain master.
if it's a remote subnet or not one of samba's workgroups, then
samba will force an election (which it is not obliged to do) and
will remove that workgroup and the servers contained in it from
its records. maybe this functionality isn't a good idea.
/*************************************************************************
check_master_browser()
*************************************************************************/
this function is responsible for periodically checking whether
master browsers that samba expects to be alive are alive. this
is done every CHECK_TIME_MST_BROWSE minutes.
for every workgroup record for which samba is not a master browser,
on both local and remote interfaces, samba will initiate a
broadcast query for a master browser on that subnet.
(browser_gone() will be called to deal with the case where no
response is received to the NAME_QUERY_MST_CHK initiated here.
no action is required when a response _is_ received, however:
see nameservresp.c:response_process() and dead_netbios_entry()
for details)

9
source3/namelogon.doc Normal file
View File

@ -0,0 +1,9 @@
this module deals with the first stage of domain logons. there is much
more work to be done on this: it's all totally undocumented.
/*************************************************************************
process_logon_packet()
*************************************************************************/
a function that processes logon packets (the most helpful comment yet :-).

106
source3/namepacket.doc Normal file
View File

@ -0,0 +1,106 @@
this module deals with packets: sending, receiving, queueing
and some basic interpretation (e.g it excludes datagram
error packets at the moment).
the packet queueing mechanism was originally introduced when
samba dealt with responses by sending a packet, receiving
packets and queueing all packets that didn't match up with
the response expected. this is fine in a single-thread
environment, but samba now deals with response packets by
queueing the responses. to some extent, therefore, this
queue_packet mechanism is redundant.
/*************************************************************************
send_mailslot_reply()
*************************************************************************/
this function is responsible for sending a MAILSLOT packet.
it will _not_ send packets to the pseudo WINS subnet's address of
255.255.255.255: this would be disastrous.
each packet sent out has a unique transaction identifier. this is done
so that responses can be matched later with the original purpose for
the packet being sent out in the first place.
/*************************************************************************
listen_for_packets()
*************************************************************************/
this function is responsible for reading NMB and DGRAM packets, and then
queueing them. it will normally time-out for NMBD_SELECT_LOOP seconds, but
if there is an election currently running or we are expecting a response
then this time is reduced to 1 second.
note: the time-out period needs refining to the millisecond level.
/*************************************************************************
queue_packet()
*************************************************************************/
this function is responsible for queueing any NMB and DGRAM packets passed
to it. these packets will be removed from the queue in run_packet_queue().
/*************************************************************************
run_packet_queue()
*************************************************************************/
this function is responsible for taking a packet off the queue,
identifying whether it is an NMB or a DGRAM packet, processing
it accordingly and deleting it. this process continues until
there are no more packets on the queue.
/*************************************************************************
process_nmb()
*************************************************************************/
this function receives a packet identified as a netbios packet.
it further identifies whether it is a response or a query packet.
by identifying the type of packet (name registration, query etc)
process_nmb() will call the appropriate function to deal with the
type of packet received.
/*************************************************************************
process_dgram()
*************************************************************************/
this function is responsible for identifying whether the datagram
packet received is a browser packet or a domain logon packet. it
also does some filtering of certain types of packets (e.g it
filters out error packets).
/*************************************************************************
reply_netbios_packet()
*************************************************************************/
this function is responsible for sending a reply to another NetBIOS
packet from another host. it can be used to send a reply to a name
registration, name release, name query or name status request.
the reply can be either a positive or a negative one.
/*************************************************************************
initiate_netbios_packet()
*************************************************************************/
this function is responsible for construction a netbios packet and sending
it. if the packet has not had a unique transaction id allocated to it,
then initiate_netbios_packet() will give it one.
/*************************************************************************
update_name_trn_id()
*************************************************************************/
this function is responsible for allocating unique transaction identifiers
for each new packet sent on the network.

56
source3/namequery.doc Normal file
View File

@ -0,0 +1,56 @@
this module contains non-threaded versions of name status and name
query functions. if a multi-threaded nmbd was to be written, these
functions would be the starting point.
at the moment, the expected response queueing system is used to
replace these functions without needing to multi-thread nmbd.
these functions are used in smbclient and nmblookup at present to
avoid having the vast quantities of complex and unused code needed
to support even a simple name query (or providing stubs for the
unused side of these functions).
there is a down-side to these functions, which is all microsoft's
fault. microsoft machines always always reply to queries on the
priveleged ports, rather than following the usual tcp/ip mechanism
of replying on the client's port (the exception to this i am led
to believe is windows nt 3.50).
as a result of this, in order to receive a response to a name
query from a microsoft machine, we must be able to listen on
the priveleged netbios name server ports. this is simply not
possible with some versions of unix, unless you have root access.
it is also not possible if you run smbclient or nmblookup on an
interface that already has been claimed by the netbios name server
daemon nmbd.
all in all, i wish that microsoft would fix this.
a solution does exist: nmbd _does_ actually reply on the client's
port, so if smbclient and nmblookup were to use nmbd as a proxy
forwarder of queries (or to use samba's WINS capabilities) then
a query could be made without needing access to the priveleged
ports. in order to do this properly, samba must implement secured
netbios name server functionality (see rfc1001.txt 15.1.6).
/*************************************************************************
name_query()
*************************************************************************/
/*************************************************************************
name_status()
*************************************************************************/
/*************************************************************************
_interpret_node_status()
*************************************************************************/
this is a older version of interpret_node_status().

View File

@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
NBT netbios library routines
Copyright (C) Andrew Tridgell 1994-1995
Copyright (C) Andrew Tridgell 1994-1996
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
@ -18,6 +18,8 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Module name: nameresp.c
*/
#include "includes.h"
@ -29,68 +31,12 @@ extern struct subnet_record *subnetlist;
extern int DEBUGLEVEL;
static uint16 name_trn_id=0;
BOOL CanRecurse = True;
extern pstring scope;
extern pstring myname;
extern struct in_addr ipzero;
extern struct in_addr ipgrp;
int num_response_packets = 0;
extern int num_response_packets;
/***************************************************************************
updates the unique transaction identifier
**************************************************************************/
static void update_name_trn_id(void)
{
if (!name_trn_id)
{
name_trn_id = (time(NULL)%(unsigned)0x7FFF) + (getpid()%(unsigned)100);
}
name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
}
/***************************************************************************
add an expected response record into the list
**************************************************************************/
static void add_response_record(struct subnet_record *d,
struct response_record *n)
{
struct response_record *n2;
if (!d) return;
if (!d->responselist)
{
d->responselist = n;
n->prev = NULL;
n->next = NULL;
return;
}
for (n2 = d->responselist; n2->next; n2 = n2->next) ;
n2->next = n;
n->next = NULL;
n->prev = n2;
}
/***************************************************************************
remove an expected response record from the list
**************************************************************************/
static void remove_response_record(struct subnet_record *d,
struct response_record *n)
{
if (n->prev) n->prev->next = n->next;
if (n->next) n->next->prev = n->prev;
if (d->responselist == n) d->responselist = n->next;
free(n);
}

/***************************************************************************
deals with an entry before it dies
@ -99,7 +45,7 @@ static void dead_netbios_entry(struct subnet_record *d,
struct response_record *n)
{
DEBUG(3,("Removing dead netbios entry for %s %s (num_msgs=%d)\n",
inet_ntoa(n->to_ip), namestr(&n->name), n->num_msgs));
inet_ntoa(n->send_ip), namestr(&n->name), n->num_msgs));
switch (n->state)
{
@ -124,7 +70,7 @@ static void dead_netbios_entry(struct subnet_record *d,
see rfc1001.txt 15.5.2
*/
remove_netbios_name(d1, n->name.name, n->name.name_type,
REGISTER, n->to_ip);
REGISTER, n->send_ip);
}
}
}
@ -139,7 +85,7 @@ static void dead_netbios_entry(struct subnet_record *d,
/* IMPORTANT: see response_netbios_packet() */
if (n->num_msgs == 0)
browser_gone(n->name.name, n->to_ip);
browser_gone(n->name.name, n->send_ip);
break;
}
@ -151,7 +97,7 @@ static void dead_netbios_entry(struct subnet_record *d,
/* IMPORTANT: see response_name_release() */
if (ismyip(n->to_ip))
if (ismyip(n->send_ip))
{
name_unregister_work(d,n->name.name,n->name.name_type);
}
@ -163,6 +109,21 @@ static void dead_netbios_entry(struct subnet_record *d,
break;
}
case NAME_REGISTER_CHALLENGE:
{
/* name challenge: no reply. we can reply to the person that
wanted the unique name and tell them that they can have it
*/
add_netbios_entry(d, n->name.name, n->name.name_type,
n->nb_flags, GET_TTL(0), REGISTER,
n->reply_to_ip, False, True);
send_name_response(n->fd, n->response_id, NMB_REG,
True, True,
&n->name, n->nb_flags, GET_TTL(0), n->reply_to_ip);
break;
}
case NAME_REGISTER:
{
/* if no response received, and we are using a broadcast registration
@ -178,7 +139,7 @@ static void dead_netbios_entry(struct subnet_record *d,
/* IMPORTANT: see response_name_reg() */
name_register_work(d,n->name.name,n->name.name_type,
n->nb_flags, n->ttl, n->to_ip, n->bcast);
n->nb_flags, n->ttl, n->send_ip, n->bcast);
}
else
{
@ -204,88 +165,12 @@ static void dead_netbios_entry(struct subnet_record *d,
}
/****************************************************************************
initiate a netbios packet
****************************************************************************/
static void initiate_netbios_packet(uint16 *id,
int fd,int quest_type,char *name,int name_type,
int nb_flags,BOOL bcast,BOOL recurse,
struct in_addr to_ip)
{
struct packet_struct p;
struct nmb_packet *nmb = &p.packet.nmb;
struct res_rec additional_rec;
char *packet_type = "unknown";
int opcode = -1;
if (!id) return;
if (quest_type == NMB_STATUS) { packet_type = "nmb_status"; opcode = 0; }
if (quest_type == NMB_QUERY ) { packet_type = "nmb_query"; opcode = 0; }
if (quest_type == NMB_REG ) { packet_type = "nmb_reg"; opcode = 5; }
if (quest_type == NMB_REL ) { packet_type = "nmb_rel"; opcode = 6; }
DEBUG(4,("initiating netbios packet: %s %s(%x) (bcast=%s) %s\n",
packet_type, name, name_type, BOOLSTR(bcast), inet_ntoa(to_ip)));
if (opcode == -1) return;
bzero((char *)&p,sizeof(p));
update_name_trn_id();
if (*id == 0xffff) *id = name_trn_id; /* allow resending with same id */
nmb->header.name_trn_id = *id;
nmb->header.opcode = opcode;
nmb->header.response = False;
nmb->header.nm_flags.bcast = bcast;
nmb->header.nm_flags.recursion_available = CanRecurse;
nmb->header.nm_flags.recursion_desired = recurse;
nmb->header.nm_flags.trunc = False;
nmb->header.nm_flags.authoritative = False;
nmb->header.rcode = 0;
nmb->header.qdcount = 1;
nmb->header.ancount = 0;
nmb->header.nscount = 0;
nmb->header.arcount = (quest_type==NMB_REG || quest_type==NMB_REL) ? 1 : 0;
make_nmb_name(&nmb->question.question_name,name,name_type,scope);
nmb->question.question_type = quest_type;
nmb->question.question_class = 0x1;
if (quest_type == NMB_REG || quest_type == NMB_REL)
{
nmb->additional = &additional_rec;
bzero((char *)nmb->additional,sizeof(*nmb->additional));
nmb->additional->rr_name = nmb->question.question_name;
nmb->additional->rr_type = nmb->question.question_type;
nmb->additional->rr_class = nmb->question.question_class;
nmb->additional->ttl = quest_type == NMB_REG ? lp_max_ttl() : 0;
nmb->additional->rdlength = 6;
nmb->additional->rdata[0] = nb_flags;
putip(&nmb->additional->rdata[2],(char *)iface_ip(to_ip));
}
p.ip = to_ip;
p.port = NMB_PORT;
p.fd = fd;
p.timestamp = time(NULL);
p.packet_type = NMB_PACKET;
if (!send_packet(&p)) *id = 0xffff;
return;
}
/*******************************************************************
remove old name response entries
XXXX retry code needs to be added, including a retry wait period and a count
see name_query() and name_status() for suggested implementation.
******************************************************************/
void expire_netbios_response_entries()
{
@ -303,7 +188,7 @@ void expire_netbios_response_entries()
/* resend the entry */
initiate_netbios_packet(&n->response_id, n->fd, n->quest_type,
n->name.name, n->name.name_type,
n->nb_flags, n->bcast, n->recurse, n->to_ip);
n->nb_flags, n->bcast, n->recurse, n->send_ip);
n->repeat_time += n->repeat_interval; /* XXXX ms needed */
n->repeat_count--;
@ -311,7 +196,6 @@ void expire_netbios_response_entries()
else
{
nextn = n->next;
num_response_packets--;
dead_netbios_entry (d,n); /* process the non-response */
remove_response_record(d,n); /* remove the non-response */
@ -324,77 +208,16 @@ void expire_netbios_response_entries()
}
/****************************************************************************
reply to a netbios name packet
****************************************************************************/
void reply_netbios_packet(struct packet_struct *p1,int trn_id,
int rcode,int opcode, BOOL recurse,
struct nmb_name *rr_name,int rr_type,int rr_class,int ttl,
char *data,int len)
{
struct packet_struct p;
struct nmb_packet *nmb = &p.packet.nmb;
struct res_rec answers;
char *packet_type = "unknown";
p = *p1;
if (rr_type == NMB_STATUS) packet_type = "nmb_status";
if (rr_type == NMB_QUERY ) packet_type = "nmb_query";
if (rr_type == NMB_REG ) packet_type = "nmb_reg";
if (rr_type == NMB_REL ) packet_type = "nmb_rel";
DEBUG(4,("replying netbios packet: %s %s\n",
packet_type, namestr(rr_name), inet_ntoa(p.ip)));
nmb->header.name_trn_id = trn_id;
nmb->header.opcode = opcode;
nmb->header.response = True;
nmb->header.nm_flags.bcast = False;
nmb->header.nm_flags.recursion_available = recurse;
nmb->header.nm_flags.recursion_desired = True;
nmb->header.nm_flags.trunc = False;
nmb->header.nm_flags.authoritative = True;
nmb->header.qdcount = 0;
nmb->header.ancount = 1;
nmb->header.nscount = 0;
nmb->header.arcount = 0;
nmb->header.rcode = 0;
bzero((char*)&nmb->question,sizeof(nmb->question));
nmb->answers = &answers;
bzero((char*)nmb->answers,sizeof(*nmb->answers));
nmb->answers->rr_name = *rr_name;
nmb->answers->rr_type = rr_type;
nmb->answers->rr_class = rr_class;
nmb->answers->ttl = ttl;
if (data && len)
{
nmb->answers->rdlength = len;
memcpy(nmb->answers->rdata, data, len);
}
p.packet_type = NMB_PACKET;
debug_nmb_packet(&p);
send_packet(&p);
}
/****************************************************************************
wrapper function to override a broadcast message and send it to the WINS
name server instead, if it exists. if wins is false, and there has been no
WINS server specified, the packet will NOT be sent.
****************************************************************************/
void queue_netbios_pkt_wins(struct subnet_record *d,
struct response_record *queue_netbios_pkt_wins(struct subnet_record *d,
int fd,int quest_type,enum state_type state,
char *name,int name_type,int nb_flags, time_t ttl,
BOOL bcast,BOOL recurse,struct in_addr to_ip)
BOOL bcast,BOOL recurse,
struct in_addr send_ip, struct in_addr reply_to_ip)
{
/* XXXX note: please see rfc1001.txt section 10 for details on this
function: it is currently inappropriate to use this - it will do
@ -411,7 +234,7 @@ void queue_netbios_pkt_wins(struct subnet_record *d,
if (!zero_ip(wins_ip))
{
bcast = False;
to_ip = wins_ip;
send_ip = wins_ip;
}
else
{
@ -421,48 +244,11 @@ void queue_netbios_pkt_wins(struct subnet_record *d,
}
}
if (zero_ip(to_ip)) return;
if (zero_ip(send_ip)) return NULL;
queue_netbios_packet(d,fd, quest_type, state,
return queue_netbios_packet(d,fd, quest_type, state,
name, name_type, nb_flags, ttl,
bcast, recurse, to_ip);
}
/****************************************************************************
create a name query response record
**************************************************************************/
static struct response_record *
make_response_queue_record(enum state_type state,int id,int fd,
int quest_type, char *name,int type, int nb_flags, time_t ttl,
BOOL bcast,BOOL recurse, struct in_addr ip)
{
struct response_record *n;
if (!name || !name[0]) return NULL;
if (!(n = (struct response_record *)malloc(sizeof(*n))))
return(NULL);
n->response_id = id;
n->state = state;
n->fd = fd;
n->quest_type = quest_type;
make_nmb_name(&n->name, name, type, scope);
n->nb_flags = nb_flags;
n->ttl = ttl;
n->bcast = bcast;
n->recurse = recurse;
n->to_ip = ip;
n->repeat_interval = 1; /* XXXX should be in ms */
n->repeat_count = 4;
n->repeat_time = time(NULL) + n->repeat_interval;
n->num_msgs = 0;
num_response_packets++; /* count of total number of packets still around */
return n;
bcast, recurse, send_ip, reply_to_ip);
}
@ -472,335 +258,30 @@ make_response_queue_record(enum state_type state,int id,int fd,
master browsers (WORKGROUP(1d or 1b) or __MSBROWSE__(1)) to get
complete lists across a wide area network
****************************************************************************/
void queue_netbios_packet(struct subnet_record *d,
struct response_record *queue_netbios_packet(struct subnet_record *d,
int fd,int quest_type,enum state_type state,char *name,
int name_type,int nb_flags, time_t ttl,
BOOL bcast,BOOL recurse, struct in_addr to_ip)
BOOL bcast,BOOL recurse,
struct in_addr send_ip, struct in_addr reply_to_ip)
{
struct in_addr wins_ip = ipgrp;
struct response_record *n;
uint16 id = 0xffff;
/* ha ha. no. do NOT broadcast to 255.255.255.255: it's a pseudo address */
if (ip_equal(wins_ip, to_ip)) return;
if (ip_equal(wins_ip, send_ip)) return NULL;
initiate_netbios_packet(&id, fd, quest_type, name, name_type,
nb_flags, bcast, recurse, to_ip);
nb_flags, bcast, recurse, send_ip);
if (id == 0xffff) return;
if (id == 0xffff) return NULL;
if ((n = make_response_queue_record(state,id,fd,
quest_type,name,name_type,nb_flags,ttl,
bcast,recurse,to_ip)))
bcast,recurse,send_ip,reply_to_ip)))
{
add_response_record(d,n);
return n;
}
return NULL;
}
/****************************************************************************
find a response in a subnet's name query response list.
**************************************************************************/
struct response_record *find_response_record(struct subnet_record **d,
uint16 id)
{
struct response_record *n;
if (!d) return NULL;
for ((*d) = subnetlist; (*d); (*d) = (*d)->next)
{
for (n = (*d)->responselist; n; n = n->next)
{
if (n->response_id == id) {
return n;
}
}
}
*d = NULL;
return NULL;
}
/*******************************************************************
the global packet linked-list. incoming entries are added to the
end of this list. it is supposed to remain fairly short so we
won't bother with an end pointer.
******************************************************************/
static struct packet_struct *packet_queue = NULL;
/*******************************************************************
queue a packet into the packet queue
******************************************************************/
void queue_packet(struct packet_struct *packet)
{
struct packet_struct *p;
if (!packet_queue) {
packet->prev = NULL;
packet->next = NULL;
packet_queue = packet;
return;
}
/* find the bottom */
for (p=packet_queue;p->next;p=p->next) ;
p->next = packet;
packet->next = NULL;
packet->prev = p;
}
/*******************************************************************
run elements off the packet queue till its empty
******************************************************************/
void run_packet_queue()
{
struct packet_struct *p;
while ((p=packet_queue))
{
switch (p->packet_type)
{
case NMB_PACKET:
process_nmb(p);
break;
case DGRAM_PACKET:
process_dgram(p);
break;
}
packet_queue = packet_queue->next;
if (packet_queue) packet_queue->prev = NULL;
free_packet(p);
}
}
/****************************************************************************
listens for NMB or DGRAM packets, and queues them
***************************************************************************/
void listen_for_packets(BOOL run_election)
{
fd_set fds;
int selrtn;
struct timeval timeout;
FD_ZERO(&fds);
FD_SET(ClientNMB,&fds);
FD_SET(ClientDGRAM,&fds);
/* during elections and when expecting a netbios response packet we need
to send election packets at one second intervals.
XXXX actually, it needs to be the interval (in ms) between time now and the
time we are expecting the next netbios packet */
timeout.tv_sec = (run_election||num_response_packets) ? 1 : NMBD_SELECT_LOOP;
timeout.tv_usec = 0;
selrtn = sys_select(&fds,&timeout);
if (FD_ISSET(ClientNMB,&fds))
{
struct packet_struct *packet = read_packet(ClientNMB, NMB_PACKET);
if (packet) {
#if 1
if (ismyip(packet->ip) &&
(packet->port == NMB_PORT || packet->port == DGRAM_PORT)) {
DEBUG(5,("discarding own packet from %s:%d\n",
inet_ntoa(packet->ip),packet->port));
free_packet(packet);
} else
#endif
{
queue_packet(packet);
}
}
}
if (FD_ISSET(ClientDGRAM,&fds))
{
struct packet_struct *packet = read_packet(ClientDGRAM, DGRAM_PACKET);
if (packet) {
#if 1
if (ismyip(packet->ip) &&
(packet->port == NMB_PORT || packet->port == DGRAM_PORT)) {
DEBUG(5,("discarding own packet from %s:%d\n",
inet_ntoa(packet->ip),packet->port));
free_packet(packet);
} else
#endif
{
queue_packet(packet);
}
}
}
}
/****************************************************************************
interpret a node status response. this is pretty hacked: we need two bits of
info. a) the name of the workgroup b) the name of the server. it will also
add all the names it finds into the namelist.
****************************************************************************/
BOOL interpret_node_status(struct subnet_record *d,
char *p, struct nmb_name *name,int t,
char *serv_name, struct in_addr ip, BOOL bcast)
{
int level = t==0x20 ? 4 : 0;
int numnames = CVAL(p,0);
BOOL found = False;
DEBUG(level,("received %d names\n",numnames));
p += 1;
if (serv_name) *serv_name = 0;
while (numnames--)
{
char qname[17];
int type;
fstring flags;
int nb_flags;
BOOL group = False;
BOOL add = False;
*flags = 0;
StrnCpy(qname,p,15);
type = CVAL(p,15);
nb_flags = p[16];
trim_string(qname,NULL," ");
p += 18;
if (NAME_GROUP (nb_flags)) { strcat(flags,"<GROUP> "); group=True;}
if (NAME_BFLAG (nb_flags)) { strcat(flags,"B "); }
if (NAME_PFLAG (nb_flags)) { strcat(flags,"P "); }
if (NAME_MFLAG (nb_flags)) { strcat(flags,"M "); }
if (NAME__FLAG (nb_flags)) { strcat(flags,"_ "); }
if (NAME_DEREG (nb_flags)) { strcat(flags,"<DEREGISTERING> "); }
if (NAME_CONFLICT (nb_flags)) { strcat(flags,"<CONFLICT> "); add=True;}
if (NAME_ACTIVE (nb_flags)) { strcat(flags,"<ACTIVE> "); add=True; }
if (NAME_PERMANENT(nb_flags)) { strcat(flags,"<PERMANENT> "); add=True;}
/* might as well update our namelist while we're at it */
if (add)
{
struct in_addr nameip;
enum name_source src;
if (ismyip(ip)) {
nameip = ipzero;
src = SELF;
} else {
nameip = ip;
src = STATUS_QUERY;
}
add_netbios_entry(d,qname,type,nb_flags,2*60*60,src,nameip,True,bcast);
}
/* we want the server name */
if (serv_name && !*serv_name && !group && t == 0)
{
StrnCpy(serv_name,qname,15);
serv_name[15] = 0;
}
/* looking for a name and type? */
if (name && !found && (t == type))
{
/* take a guess at some of the name types we're going to ask for.
evaluate whether they are group names or no... */
if (((t == 0x1b || t == 0x1d ) && !group) ||
((t == 0x20 || t == 0x1c || t == 0x1e) && group))
{
found = True;
make_nmb_name(name,qname,type,scope);
}
}
DEBUG(level,("\t%s(0x%x)\t%s\n",qname,type,flags));
}
DEBUG(level,("num_good_sends=%d num_good_receives=%d\n",
IVAL(p,20),IVAL(p,24)));
return found;
}
/****************************************************************************
construct and send a netbios DGRAM
Note that this currently sends all answers to port 138. thats the
wrong things to do! I should send to the requestors port. XXX
**************************************************************************/
BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname,
char *dstname,int src_type,int dest_type,
struct in_addr dest_ip,struct in_addr src_ip)
{
struct packet_struct p;
struct dgram_packet *dgram = &p.packet.dgram;
struct in_addr wins_ip = ipgrp;
char *ptr,*p2;
char tmp[4];
/* ha ha. no. do NOT send packets to 255.255.255.255: it's a pseudo address */
if (ip_equal(wins_ip, dest_ip)) return False;
bzero((char *)&p,sizeof(p));
update_name_trn_id();
dgram->header.msg_type = 0x11; /* DIRECT GROUP DATAGRAM */
dgram->header.flags.node_type = M_NODE;
dgram->header.flags.first = True;
dgram->header.flags.more = False;
dgram->header.dgm_id = name_trn_id;
dgram->header.source_ip = src_ip;
dgram->header.source_port = DGRAM_PORT;
dgram->header.dgm_length = 0; /* let build_dgram() handle this */
dgram->header.packet_offset = 0;
make_nmb_name(&dgram->source_name,srcname,src_type,scope);
make_nmb_name(&dgram->dest_name,dstname,dest_type,scope);
ptr = &dgram->data[0];
/* now setup the smb part */
ptr -= 4; /* XXX ugliness because of handling of tcp SMB length */
memcpy(tmp,ptr,4);
set_message(ptr,17,17 + len,True);
memcpy(ptr,tmp,4);
CVAL(ptr,smb_com) = SMBtrans;
SSVAL(ptr,smb_vwv1,len);
SSVAL(ptr,smb_vwv11,len);
SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
SSVAL(ptr,smb_vwv13,3);
SSVAL(ptr,smb_vwv14,1);
SSVAL(ptr,smb_vwv15,1);
SSVAL(ptr,smb_vwv16,2);
p2 = smb_buf(ptr);
strcpy(p2,mailslot);
p2 = skip_string(p2,1);
memcpy(p2,buf,len);
p2 += len;
dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length */
p.ip = dest_ip;
p.port = DGRAM_PORT;
p.fd = ClientDGRAM;
p.timestamp = time(NULL);
p.packet_type = DGRAM_PACKET;
return(send_packet(&p));
}

View File

@ -1,12 +1,15 @@
the netbios expected response code is a key part of samba's NetBIOS
handling capabilities. it allows samba to carry on dealing with
other things while expecting a response from one or more hosts.
this allows samba to simultaneously deal with registering its names
with another WINS server, register its names on its local subnets,
query any hosts that have registered with samba in its capacity as
a WINS server, and at a later date it will be also be able handle
END-NODE CHALLENGES (see rfc1001.txt 15.2.2.2 and 15.2.2.3 - secured
NBNS functionality). all at once!
NBNS functionality).
all at once!
when a netbios packet is sent out by samba and it expects a response,
a record of all the relevant information is kept (most importantly,
@ -21,76 +24,15 @@ made (and therefore the type of response can be verified) and
appropriate action can be taken.
when no responses, after a number of retries, are not received, then
samba may take appropriate action.
samba may take appropriate action. this is a crucial part of samba's
operation: for a key number of NetBIOS operations, no response is an
implicit positive response.
nameresp.c deals with the maintenance of the netbios response records:
their creation, retransmission, and eventual removal.
module nameresp deals with the initial transmission, re-transmission
and time-out of netbios response records.
/*************************************************************************
send_mailslot_reply()
*************************************************************************/
this function is responsible for sending a MAILSLOT packet.
it will _not_ send packets to the pseudo WINS subnet's address of
255.255.255.255: this would be disastrous.
each packet sent out has a unique transaction identifier. this is done
so that responses can be matched with the original purpose for the packet
being sent out in the first place.
/*************************************************************************
interpret_node_status()
*************************************************************************/
this function is responsible for interpreting the raw data that comes in
from a node status reply. in the process, it identifies both the server
name and the workgroup name in the node status reply.
it also updates information in the WINS name database if the names
received are not already in samba's records.
/*************************************************************************
listen_for_packets()
*************************************************************************/
this function is responsible for reading NMB and DGRAM packets, and then
queueing them. it will normally time-out for NMBD_SELECT_LOOP seconds, but
if there is an election currently running or we are expecting a response
then this time is reduced to 1 second.
note: the time-out period needs refining to the millisecond level.
/*************************************************************************
queue_packet()
*************************************************************************/
this function is responsible for queueing any NMB and DGRAM packets passed
to it. these packets will be removed from the queue in run_packet_queue().
/*************************************************************************
run_packet_queue()
*************************************************************************/
this function is responsible for taking a packet off the queue,
identifying whether it is an NMB or a DGRAM packet, processing
it accordingly and deleting it. this process continues until
there are no more packets on the queue.
/*************************************************************************
find_response_record()
*************************************************************************/
this function is responsible for matching the unique response transaction
id with an expected response record. as a side-effect of this search,
it will find the subnet (or the WINS pseudo-subnet) that samba expected
the response to come from.
module namedbresp deals with the maintenance of the list of expected
responses - creation, finding and removal.
/*************************************************************************
@ -105,22 +47,6 @@ if a response is received, response_netbios_packet() will deal with it.
otherwise, it will be dealt with in expire_netbios_response_entries().
/*************************************************************************
make_response_queue_record()
*************************************************************************/
this function is responsible for creating a response record, which will
be queued awaiting a response.
the number of retries is set to 4, and the retry period set to 1 second.
if no response is received, then the packet is re-transmitted, which is
why so much information is stored in the response record.
the number of expected responses queued is kept, so listen_for_packets()
knows it must time-out after 1 second if one or more responses are
expected.
/*************************************************************************
queue_netbios_pkt_wins()
*************************************************************************/
@ -137,17 +63,6 @@ name.
this is NOT the case with a P node.
/*************************************************************************
reply_netbios_packet()
*************************************************************************/
this function is responsible for sending a reply to another NetBIOS
packet from another host. it can be used to send a reply to a name
registration, name release, name query or name status request.
the reply can be either a positive or a negative one.
/*************************************************************************
expire_netbios_response_entries()
*************************************************************************/
@ -173,15 +88,6 @@ will no longer time-out for 1 second on account of expecting response
packets.
/*************************************************************************
initiate_netbios_packet()
*************************************************************************/
this function is responsible for construction a netbios packet and sending
it. if the packet has not had a unique transaction id allocated to it,
then initiate_netbios_packet() will give it one.
/*************************************************************************
dead_netbios_entry()
*************************************************************************/
@ -225,6 +131,18 @@ samba should take this into account (see rfc1001.txt 10.3).
remove_name_entry() issues this samba 'state'
response_name_rel() deals with responses to NAME_RELEASE.
- NAME_REGISTER_CHALLENGE
when a samba 'state' of type NAME_REGISTER_CHALLENGE is sent, and a
response is not received, it is assumed that the server being queried
is either dead, deaf or unreachable. the host that wanted this
unique name is then informed that it can have it (the name query
challenge went unanswered) and that its registration of this name
did in fact succeed.
reply_name_reg() issues this samba 'state'
response_name_query_register() deals with responses.
- NAME_REGISTER
when a samba 'state' of type NAME_REGISTER is sent, and a response is
@ -243,19 +161,3 @@ is not received. this is not to say that action may not be appropriate,
just that it's not been looked at yet :-)
/*************************************************************************
add_response_record()
*************************************************************************/
this function is responsible for adding the response record created by
make_response_queue_record() into the appropriate response record queue.
/*************************************************************************
update_name_trn_id()
*************************************************************************/
this function is responsible for allocating unique transaction identifiers
for each new packet sent on the network.

File diff suppressed because it is too large Load Diff

View File

@ -1,344 +1,4 @@
/*************************************************************************
process_nmb()
*************************************************************************/
this function receives a packet identified as a netbios packet.
it further identifies whether it is a response or a query packet.
by identifying the type of packet (name registration, query etc)
process_nmb() will call the appropriate function to deal with the
type of packet received.
/*************************************************************************
response_netbios_packet()
*************************************************************************/
this function received netbios response packets. the samba server
(or a rogue tcp/ip system, or nmblookup) will have sent out a packet
requesting a response. a client (or a rogue tcp/ip system) responds
to that request.
this function checks the validity of the packet it receives.
the expected response records are searched for the transaction id,
to see if it's a response expected by the samba server. if it isn't
it's reported as such, and ignored.
if the response is found, then the subnet it was expected from will
also have been found. the subnet it actually came in on can be
checked against the subnet it was expected from and reported,
otherwise this function just carries on.
the number of responses received is increased, and the number of
retries left to be sent is set to zero.
after debug information is reported, and validation of the netbios
packet (e.g only one response from one machine is expected for some
functions) has occurred, the packet is processed. when the initial
request was sent out, the expected response record was flagged with,
for lack of a better word, a samba 'state' type. whenever a
response is received, the appropriate function is called to carry on
where the program control flow was interrupted while awaiting exactly
such a response.
please note that _not_ receiving a response is dealt with in another
area of code - expire_netbios_response_entries().
/*************************************************************************
response_name_query_sync()
*************************************************************************/
this function receives responses to samba 'states' NAME_QUERY_SYNC and
NAME_QUERY_CONFIRM.
NAME_QUERY_SYNC: name query a server before synchronising browse lists.
NAME_QUERY_CONFIRM: name query a server to check that it's alive.
a NAME_QUERY_SYNC will be carried out in order to check that a server
is alive before syncing browse lists. we don't want to delay the SMB
NetServerEnum api just because the server has gone down: we have too
much else to do.
a NAME_QUERY_CONFIRM is just a name query to see whether the server is
alive. these queries are sent out by samba's WINS server side, to verify
its netbios name database of all machines that have registered with it.
we don't normally expect a negative response from such a query, although
we may do so if the query was sent to another WINS server. the registered
entry should be removed if we receive a negative response.
/*************************************************************************
response_name_status_check()
*************************************************************************/
this function receives responses to samba 'states' NAME_STATUS_CHECK
and NAME_STATUS_MASTER_CHECK
NAME_STATUS_MASTER_CHECK: name status a primary domain controller,
confirm its domain and then initiate syncing
its browse list.
NAME_STATUS_CHECK: same as NAME_STATUS_MASTER_CHECK except the name status
is issued to a master browser.
if we don't know what workgroup a server is responsible for, but we
know that there is a master browser at a certain ip, we can issue a
name status check. from the response received, there will be
a master browser netbios entry. this will allow us to synchronise
browse lists with that machine and then add the information to the
correct part of samba's workgroup - server database.
/*************************************************************************
response_server_check()
*************************************************************************/
this function receives responses to samba 'states' NAME_QUERY_MST_SRV_CHK,
NAME_QUERY_SRV_CHK and NAME_QUERY_FIND_MST.
NAME_QUERY_FIND_MST: issued as a broadcast when we wish to find out all
master browsers (i.e all servers that have registered
the NetBIOS name ^1^2__MSBROWSE__^2(0x1), and then
issue a NAME_STATUS_MASTER_CHECK on any servers that
respond, which will initiate a sync browse lists.
NAME_QUERY_MST_SRV_CHK: same as a NAME_QUERY_FIND_MST except this is sent
to a primary domain controller.
NAME_QUERY_SRV_CHK: same as a NAME_QUERY_MST_SRV_CHK except this is sent to
a master browser.
the purpose of each of these states is to do a broadcast name query, or
a name query directed at a WINS server, then to all hosts that respond,
we issue a name status check, which will confirm for us the workgroup
or domain name, and then initiate issuing a sync browse list call with
that server.
a NAME_QUERY_SRV_CHK is sent when samba receives a list of backup
browsers. it checks to see if that server is alive (by doing a
name query on a server) and then syncs browse lists with it.
/*************************************************************************
reply_name_query()
*************************************************************************/
this function is responsible for replying to a NetBIOS name query.
there are two kinds of name queries: directed, and broadcast. directed
queries are usually sent to samba in its WINS capacity. such hosts are
termed 'point-to-point' hosts. broadcast queries are usually sent from
'broadcast' or 'mixed' hosts.
broadcasting is used by either older NetBIOS hosts, new NetBIOS hosts that
have not had WINS capabilities added and new NetBIOS hosts that think the
WINS server has died.
the samba NetBIOS name database is divided into sections, on a
per-subnet basis. there is also a WINS NetBIOS name database, and for
convenience this is added as a pseudo-subnet with the ip address of
255.255.255.255.
the local subnet NetBIOS name databases only contain samba's names.
the reason for this is that if a broadcast query is received, a NetBIOS
hosts is only expected to respond if that query is for one of its own
names (the exception to this is if a host is configured as a 'proxy'
server, in which case, samba should redirect the query to another WINS
server).
the WINS pseudo-subnet NetBIOS database contains all NetBIOS names
that are not 'special browser' type names (regarding this i am a
_bit_ confused :-). names of type 0x01, 0x1d and 0x1e i consider to
be 'special browser' names. at the moment. maybe.
the type of search to be initiated is determined. if the NetBIOS name
type is a non-special-browser name, then the WINS database is included
in the search.
if the name is not a special browser name, then we need to find the
right subnet that the query came from. this is done using
find_req_subnet(). this also has the benefit of stopping any queries
from subnets that samba does not know about.
if the query is a broadcast query, then the database of the local subnet
is included in the search.
the name is then searched for in the appropriate NetBIOS data structures.
if it is found, then we need to check whether it is appropriate for us
to reply to such a query.
we will only reply if the query is a directed query, the name belongs to
samba on that subnet, or the name is a primary domain controller type,
or we're doing replies on behalf of hosts on subnets not known to the
host issuing the query. in the latter instance, it would be appropriate
if samba is using a WINS server for it to forward the name query on to
this WINS server.
reply_name_query() then takes note of all the information that is
needed to construct a reply to the caller. a negative reply (if the
name is unknown to samba) or a positive reply (the name is known to
samba) is then issued.
/*************************************************************************
search_for_name()
*************************************************************************/
this function is responsible for finding a name in the appropriate part
of samba's NetBIOS name database. if the name cannot be found, then it
should look the name up using DNS. later modifications will be to
forward the request on to another WINS server, should samba not be able
to find out about the requested name (this will be implemented through
issuing a new type of samba 'state').
the name is first searched for in the NetBIOS cache. if it cannot be
found, then it if the name looks like it's a server-type name (0x20
0x0 or 0x1b) then DNS is used to look for the name.
if DNS fails, then a record of this failure is kept. if it succeeds, then
a new NetBIOS entry is added.
the successfully found name is returned. on failure, NULL is returned.
/*************************************************************************
reply_name_status()
*************************************************************************/
this function is responsible for constructing a reply to a NetBIOS
name status query. this response contains all samba's NetBIOS names
on the subnet that the query came in from.
a reply will only be made if the NetBIOS name being queried exists.
see rfc1001.txt and rfc1002.txt for details of the name status reply.
/*************************************************************************
reply_name_reg()
*************************************************************************/
this function is responsible for updating the NetBIOS name database
from registration packets sent out by hosts wishing to register a
name, and for informing them, if necessary, if this is acceptable
or not.
name registration can be done by broadcast or by point-to-point,
i.e the registration is sent directly to samba in its capacity as
a WINS server.
if the name registration is done by broadcast (see rfc1001.txt 15.2.1),
then samba's involvement in replying is limited to whether that name
is owned by samba or not, on the relevant subnet.
if the name registration is done point-to-point (see rfc1001.txt 15.2.2)
then samba will first need to check its WINS name database records and
proceed accordingly.
samba looks for the appropriate subnet record that the registration
should be added to / checked against, using find_req_subnet().
next, the name is searched for in the local database or the WINS
database as appropriate.
if the name is not found, then it is added to the NetBIOS name database,
using add_netbios_entry(), which may choose not to add the name (not
that this affects the registration of the name on the network in any way).
it will only add names to the WINS database, and even then it will only
add non-special-browser type names.
if the name is found, then samba must decide whether to accept the name
or not. a group name is always added. for unique names, further checks
need to be carried out.
firstly, if the name in the database is one of samba's names, or if the
name in the database is a group name, then it cannot be added as a unique
name belonging to someone else. it is therefore rejected.
secondly, if the ip address of the name being registered does not match
against the ip in the database, then the unique name may belong to
someone else. a check needs to be carried out with the owner in case
they still wish to keep this name. a detailed discussion of what action
to take is in rfc1001.txt 15.2.2.2 and 15.2.2.3.
samba currently implements non-secured WINS, whereupon the responsibility
for checking the name is passed on to the host doing the registration.
rfc1001.txt refers to this as an END-NODE CHALLENGE REGISTRATION RESPONSE.
(samba itself cannot yet cope with receiving such responses if it
registers its names with another WINS server).
having decided what kind of response to send (if any - acceptance of
name registrations by broadcast is implicit), samba will send either a
positive or negative NAME REGISTRATION RESPONSE, or an END-NODE CHALLENGE
REGISTRATION RESPONSE to the host that initially sent the registration.
whew.
/*************************************************************************
response_name_reg()
*************************************************************************/
this function is responsible for dealing with samba's registration
attempts, by broadcast to a local subnet, or point-to-point with
another WINS server.
please note that it cannot cope with END-NODE CHALLENGE REGISTRATION
RESPONSEs at present.
when a response is received, samba determines if the response is a
positive or a negative one. if it is a positive response, the name
is added to samba's database.
when a negative response is received, samba will remove the name
from its database. if, however, the name is a browser type (0x1b is
a primary domain controller type name; or 0x1d, which is a master
browser type name) then it must also stop being a primary domain
controller or master browser respectively, depending on what kind
of name was rejected.
(when no response is received, then expire_netbios_response_entries()
is expected to deal with this. the only case that is dealt with here
at present is when the registration was done by broadcast. if there
is no challenge to the broadcast registration, it is implicitly
assumed that claiming the name is acceptable).
/*************************************************************************
response_name_release()
*************************************************************************/
this function is responsible for removing samba's NetBIOS name when
samba contacts another WINS server with which it had registered the
name.
only positive name releases are expected and dealt with. exactly what
to do if a negative name release (i.e someone says 'oi! you have to
keep that name!') is received is uncertain.
(when no response is received, then expire_netbios_response_entries()
is expected to deal with this. if there is no challenge to the release
of the name, the name is then removed from that subnet's NetBIOS
name database).
/*************************************************************************
expire_names()
*************************************************************************/
this function is responsible for removing old NetBIOS names from its
database. no further action is required.
for over-zealous WINS systems, the use of query_refresh_names() is
recommended. this function initiates polling of hosts that have
registered with samba in its capacity as a WINS server. an alternative
means to achieve the same end as query_refresh_names() is to
reduce the time to live when the name is registered with samba,
except that in this instance the responsibility for refreshing the
name is with the owner of the name, not the server with which the name
is registered.
this module deals with general maintenance of NetBIOS names.
/*************************************************************************
query_refresh_names()
@ -436,45 +96,3 @@ are recorded in this file, including the time-to-live. should the
time left to live be small, the name is not added back in to samba's
WINS database.
/*************************************************************************
dump_names()
*************************************************************************/
this function is responsible for outputting NetBIOS names in two formats.
firstly, as debugging information, and secondly, all names that have been
registered with samba in its capacity as a WINS server are written to
disk.
writing all WINS names allows two things. firstly, if samba's NetBIOS
daemon dies or is terminated, on restarting the daemon most if not all
of the registered WINS names will be preserved (which is a good reason
why query_netbios_names() should be used).
/*************************************************************************
find_name_search()
*************************************************************************/
this function is a wrapper around find_name(). find_name_search() can
be told whether to search for the name in a local subnet structure or
in the WINS database. on top of this, it can be told to search only
for samba's SELF names.
if it finds the name in the WINS database, it will set the subnet_record
and also return the name it finds.
/*************************************************************************
find_req_subnet()
*************************************************************************/
this function is responsible for finding the appropriate subnet record
to use. it is assumed that any directed packets are going to need to
use the WINS pseudo-subnet records, and that any broadcast transactions
received are going to need to use a local subnet record, which is found
from the ip address that the transaction was received on.
a side-effect of this function is that any broadcast packet received
on a subnet not known to samba is ignored.

189
source3/nameservreply.doc Normal file
View File

@ -0,0 +1,189 @@
/*************************************************************************
reply_name_query()
*************************************************************************/
this function is responsible for replying to a NetBIOS name query.
there are two kinds of name queries: directed, and broadcast. directed
queries are usually sent to samba in its WINS capacity. such hosts are
termed 'point-to-point' hosts. broadcast queries are usually sent from
'broadcast' or 'mixed' hosts.
broadcasting is used by either older NetBIOS hosts, new NetBIOS hosts that
have not had WINS capabilities added and new NetBIOS hosts that think the
WINS server has died.
the samba NetBIOS name database is divided into sections, on a
per-subnet basis. there is also a WINS NetBIOS name database, and for
convenience this is added as a pseudo-subnet with the ip address of
255.255.255.255.
the local subnet NetBIOS name databases only contain samba's names.
the reason for this is that if a broadcast query is received, a NetBIOS
hosts is only expected to respond if that query is for one of its own
names (the exception to this is if a host is configured as a 'proxy'
server, in which case, samba should redirect the query to another WINS
server).
the WINS pseudo-subnet NetBIOS database contains all NetBIOS names
registered with samba in its capacity as a WINS server.
the type of search to be initiated is determined. if the packet
received is a point-to-point (unicast), then the WINS database
is included in the search.
if the search is not in the WINS database, then we need to find the
right subnet that the query came from. this is done using
find_req_subnet(). this also has the benefit of stopping any queries
from subnets that samba does not know about.
if the query is a broadcast query, then the database of the local subnet
is included in the search.
the name is then searched for in the appropriate NetBIOS data structures.
if it is found, then we need to check whether it is appropriate for us
to reply to such a query.
we will only reply if the query is a directed query, the name belongs to
samba on that subnet, or the name is a primary domain controller type,
or we're doing replies on behalf of hosts on subnets not known to the
host issuing the query. in the latter instance, it would be appropriate
if samba is using a WINS server for it to forward the name query on to
this WINS server.
reply_name_query() then takes note of all the information that is
needed to construct a reply to the caller. a negative reply (if the
name is unknown to samba) or a positive reply (the name is known to
samba) is then issued.
/*************************************************************************
reply_name_status()
*************************************************************************/
this function is responsible for constructing a reply to a NetBIOS
name status query. this response contains all samba's NetBIOS names
on the subnet that the query came in from.
a reply will only be made if the NetBIOS name being queried exists.
see rfc1001.txt and rfc1002.txt for details of the name status reply.
/*************************************************************************
reply_name_reg()
*************************************************************************/
this function is responsible for updating the NetBIOS name database
from registration packets sent out by hosts wishing to register a
name, and for informing them, if necessary, if this is acceptable
or not.
name registration can be done by broadcast or by point-to-point,
i.e the registration is sent directly to samba in its capacity as
a WINS server.
if the name registration is done by broadcast (see rfc1001.txt 15.2.1),
then samba's involvement in replying is limited to whether that name
is owned by samba or not, on the relevant subnet.
if the name registration is done point-to-point (see rfc1001.txt 15.2.2)
then samba will first need to check its WINS name database records and
proceed accordingly.
samba looks for the appropriate subnet record that the registration
should be added to / checked against, using find_req_subnet().
next, the name is searched for in the local database or the WINS
database as appropriate.
if the name is not found, then it is added to the NetBIOS name database,
using add_netbios_entry(), which may choose not to add the name (not
that this affects the registration of the name on the network in any way).
it will only add non-SELF names to the WINS database.
if the name is found, then samba must decide whether to accept the name
or not. a group name is always added. for unique names, further checks
need to be carried out.
firstly, if the name in the database is one of samba's names, or if the
name in the database is a group name, then it cannot be added as a unique
name belonging to someone else. it is therefore rejected.
secondly, if the ip address of the name being registered does not match
against the ip in the database, then the unique name may belong to
someone else. a check needs to be carried out with the owner in case
they still wish to keep this name. a detailed discussion of what action
to take is in rfc1001.txt 15.2.2.2 and 15.2.2.3.
#if 0
samba currently implements non-secured WINS, whereupon the responsibility
for checking the name is passed on to the host doing the registration.
rfc1001.txt refers to this as an END-NODE CHALLENGE REGISTRATION RESPONSE.
(samba itself cannot yet cope with receiving such responses if it
registers its names with another WINS server).
#else
samba currently implements secured WINS, whereupon it is samba's
responsibility to check the unique name before allowing it to be
registered by the new owner.
as checking the unique name may take some time, samba must send a Wait
Acknowledge packet to the host that wishes to claim the name. a
NAME_REGISTER_CHALLENGE 'state' is then initiated, which will result
in a name query being issued to the current owner.
if we receive a negative response or no response, the host wishing
to claim the name is informed that they can have it. if we receive
a positive response, this host is informed that it cannot have it.
#endif
having decided what kind of response to send (if any - acceptance of
name registrations by broadcast is implicit), samba will send a
positive or negative NAME REGISTRATION RESPONSE, or an END-NODE CHALLENGE
REGISTRATION RESPONSE or a WAIT ACKNOWLEDGEMENT to the host that
initially sent the registration.
whew.
/*************************************************************************
send_name_response()
*************************************************************************/
this function is responsible for sending out a positive or a negative
registration response or release, or an end-node challenge registration
response.
it is called from reply_name_release(), reply_name_reg(),
dead_netbios_entry() and response_name_query_register().
/*************************************************************************
reply_name_release()
*************************************************************************/
this function is responsible for removing a NetBIOS name from the
database when a server sends a release packet.
samba looks for the appropriate subnet record that the release should
be removed from, using find_req_subnet(). next, the name is searched
for in the local database or the WINS database as appropriate.
if the name is found, it is removed from the database and a
positive reply is sent confirming this. if the name is not
found, a negative reply is sent.
a reply is _not_ sent if the release was done by broadcast: the
release is implicit, and we should be grateful that they bothered
to tell us. if the release was done by directed packet, then
we deal with it as a WINS server and must reply (pos / neg).
at present, the criteria for removing a name have yet to be
developed / experimented with. at present, the only flags that
are checked are the NetBIOS flags.

188
source3/nameservresp.doc Normal file
View File

@ -0,0 +1,188 @@
this module deals with the receipt of response packets. the
response packets are expected to be received, and there is a
record of this kept (see also: modules nameresp and namedbresp)
/*************************************************************************
response_netbios_packet()
*************************************************************************/
this function receives netbios response packets. the samba server
(or a rogue tcp/ip system, or nmblookup) will have sent out a packet
requesting a response. a client (or a rogue tcp/ip system) responds
to that request.
this function checks the validity of the packet it receives.
the expected response records are searched for the transaction id,
to see if it's a response expected by the samba server. if it isn't
it's reported as such, and ignored.
if the response is found, then the subnet it was expected from will
also have been found. the subnet it actually came in on can be
checked against the subnet it was expected from and reported,
otherwise this function just carries on.
the number of responses received is increased, and the number of
retries left to be sent is set to zero.
after debug information is reported, and validation of the netbios
packet (e.g only one response from one machine is expected for some
functions) has occurred, the packet is processed. when the initial
request was sent out, the expected response record was flagged with,
for lack of a better word, a samba 'state' type. whenever a
response is received, the appropriate function is called to carry on
where the program control flow was interrupted while awaiting exactly
such a response.
please note that _not_ receiving a response is dealt with in another
area of code - expire_netbios_response_entries().
/*************************************************************************
response_name_query_sync()
*************************************************************************/
this function receives responses to samba 'states' NAME_QUERY_SYNC and
NAME_QUERY_CONFIRM.
NAME_QUERY_SYNC: name query a server before synchronising browse lists.
NAME_QUERY_CONFIRM: name query a server to check that it's alive.
a NAME_QUERY_SYNC will be carried out in order to check that a server
is alive before syncing browse lists. we don't want to delay the SMB
NetServerEnum api just because the server has gone down: we have too
much else to do.
a NAME_QUERY_CONFIRM is just a name query to see whether the server is
alive. these queries are sent out by samba's WINS server side, to verify
its netbios name database of all machines that have registered with it.
we don't normally expect a negative response from such a query, although
we may do so if the query was sent to another WINS server. the registered
entry should be removed if we receive a negative response.
/*************************************************************************
response_name_query_register()
*************************************************************************/
this function receives responses to samba 'states'
NAME_REGISTER_CHALLENGE.
NAME_REGISTER_CHALLENGE: name query a server to establish whether to
hand over a unique name to another server that asked for that name.
if a positive response is received to the name query, this indicates
that the current owner still wants the name. we therefore refresh
the name records indicating that the current owner still wants it,
and we inform the potential owner (the other host) that they cannot
have it.
if a negative response is received, this indicates that for some
reason (for example, it may have just released the name or the
WINS server may have had out-of-date records) the current owner
does not want the name. in this instance, the name records are
updated to give this unique name to the other host that wanted
it, and the other host is informed that they can have it.
a failure to respond on the part of the current owner of the name
is dealt with in dead_netbios_entry().
/*************************************************************************
response_name_status_check()
*************************************************************************/
this function receives responses to samba 'states' NAME_STATUS_CHECK
and NAME_STATUS_MASTER_CHECK
NAME_STATUS_MASTER_CHECK: name status a primary domain controller,
confirm its domain and then initiate syncing
its browse list.
NAME_STATUS_CHECK: same as NAME_STATUS_MASTER_CHECK except the name status
is issued to a master browser.
if we don't know what workgroup a server is responsible for, but we
know that there is a master browser at a certain ip, we can issue a
name status check. from the response received, there will be
a master browser netbios entry. this will allow us to synchronise
browse lists with that machine and then add the information to the
correct part of samba's workgroup - server database.
/*************************************************************************
response_server_check()
*************************************************************************/
this function receives responses to samba 'states' NAME_QUERY_MST_SRV_CHK,
NAME_QUERY_SRV_CHK and NAME_QUERY_FIND_MST.
NAME_QUERY_FIND_MST: issued as a broadcast when we wish to find out all
master browsers (i.e all servers that have registered
the NetBIOS name ^1^2__MSBROWSE__^2(0x1), and then
issue a NAME_STATUS_MASTER_CHECK on any servers that
respond, which will initiate a sync browse lists.
NAME_QUERY_MST_SRV_CHK: same as a NAME_QUERY_FIND_MST except this is sent
to a primary domain controller.
NAME_QUERY_SRV_CHK: same as a NAME_QUERY_MST_SRV_CHK except this is sent to
a master browser.
the purpose of each of these states is to do a broadcast name query, or
a name query directed at a WINS server, then to all hosts that respond,
we issue a name status check, which will confirm for us the workgroup
or domain name, and then initiate issuing a sync browse list call with
that server.
a NAME_QUERY_SRV_CHK is sent when samba receives a list of backup
browsers. it checks to see if that server is alive (by doing a
name query on a server) and then syncs browse lists with it.
/*************************************************************************
response_name_reg()
*************************************************************************/
this function is responsible for dealing with samba's registration
attempts, by broadcast to a local subnet, or point-to-point with
another WINS server.
please note that it cannot cope with END-NODE CHALLENGE REGISTRATION
RESPONSEs at present.
when a response is received, samba determines if the response is a
positive or a negative one. if it is a positive response, the name
is added to samba's database.
when a negative response is received, samba will remove the name
from its database. if, however, the name is a browser type (0x1b is
a primary domain controller type name; or 0x1d, which is a master
browser type name) then it must also stop being a primary domain
controller or master browser respectively, depending on what kind
of name was rejected.
(when no response is received, then expire_netbios_response_entries()
is expected to deal with this. the only case that is dealt with here
at present is when the registration was done by broadcast. if there
is no challenge to the broadcast registration, it is implicitly
assumed that claiming the name is acceptable).
/*************************************************************************
response_name_release()
*************************************************************************/
this function is responsible for removing samba's NetBIOS name when
samba contacts another WINS server with which it had registered the
name.
only positive name releases are expected and dealt with. exactly what
to do if a negative name release (i.e someone says 'oi! you have to
keep that name!') is received is uncertain.
(when no response is received, then expire_netbios_response_entries()
is expected to deal with this. if there is no challenge to the release
of the name, the name is then removed from that subnet's NetBIOS
name database).

View File

@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
NBT netbios routines and daemon - version 2
Copyright (C) Andrew Tridgell 1994-1995
Copyright (C) Andrew Tridgell 1994-1996
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
@ -64,8 +64,6 @@ extern int updatecount;
extern time_t StartupTime;
#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
/****************************************************************************
tell a server to become a backup browser
@ -385,7 +383,7 @@ static void process_rcv_backup_list(struct packet_struct *p,char *buf)
{
queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
work->work_group,0x1d,0,0,
False,False,back_ip);
False,False,back_ip,back_ip);
return;
}
}
@ -812,49 +810,3 @@ void process_browse_packet(struct packet_struct *p,char *buf,int len)
}
/****************************************************************************
process udp 138 datagrams
****************************************************************************/
void process_dgram(struct packet_struct *p)
{
char *buf;
char *buf2;
int len;
struct dgram_packet *dgram = &p->packet.dgram;
if (dgram->header.msg_type != 0x10 &&
dgram->header.msg_type != 0x11 &&
dgram->header.msg_type != 0x12) {
/* don't process error packets etc yet */
return;
}
buf = &dgram->data[0];
buf -= 4; /* XXXX for the pseudo tcp length -
someday I need to get rid of this */
if (CVAL(buf,smb_com) != SMBtrans) return;
len = SVAL(buf,smb_vwv11);
buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
DEBUG(4,("datagram from %s to %s for %s of type %d len=%d\n",
namestr(&dgram->source_name),namestr(&dgram->dest_name),
smb_buf(buf),CVAL(buf2,0),len));
if (len <= 0) return;
/* datagram packet received for the browser mailslot */
if (strequal(smb_buf(buf),BROWSE_MAILSLOT)) {
process_browse_packet(p,buf2,len);
return;
}
/* datagram packet received for the domain log on mailslot */
if (strequal(smb_buf(buf),NET_LOGON_MAILSLOT)) {
process_logon_packet(p,buf2,len);
return;
}
}

View File

@ -2,26 +2,15 @@
the module namework.c deals with NetBIOS datagram packets, primarily.
it deals with nmbd's workgroup browser side and the domain log in
side. none of the functionality here has specification documents available.
empirical observation of packet traces has been the order of the day.
empirical observation of packet traces has been the order of the day,
along with some guess-work.
beware!
the receipt of datagram packets for workgroup browsing are dealt with here.
some of the functions listed here will call others outside of this
module, or will activate functionality dealt with by other modules.
these include: namedb.c, nameannounce.c, nameelect.c,
namelogon.c, and namebrowse.c.
/*************************************************************************
process_dgram()
*************************************************************************/
this function is responsible for identifying whether the datagram
packet received is a browser packet or a domain logon packet. it
also does some filtering of certain types of packets (e.g it
filters out error packets).
module, or will activate functionality dealt with by other modules
(namedb, nameannounce, nameelect, namelogon, and namebrowse).
/*************************************************************************
@ -95,7 +84,8 @@ samba do not implement this latter option.
this datagram is sent by a master browser to a primary domain
controller. it is a way to ensure that master browsers are
kept in sync with a primary domain controller across a wide
area network.
area network. on receipt of an ANN_MasterAnnouncement we
should sync browse lists with the sender.
(i never got the hang of this one when i was experimenting.
i forget exactly what it's for, and i never fully worked