From e5a0619c2839d45b00446c3af3f30599f3f3c5fa Mon Sep 17 00:00:00 2001 From: Samba Release Account Date: Wed, 10 Jul 1996 18:48:49 +0000 Subject: [PATCH] updated docs to match code mods from last two or three updates. done some more commenting of code to match docs. sorted some bugs. ipc BOOL domains was uninitialised. lkcl (This used to be commit cb43ce7bc08fa43a6ce49e0937f13afec5dce67b) --- source3/include/proto.h | 8 +- source3/namedb.c | 707 -------------------------------------- source3/namedbresp.doc | 2 +- source3/namedbsubnet.c | 9 +- source3/nameelect.c | 23 +- source3/nameelect.doc | 15 +- source3/nameresp.c | 28 +- source3/nameserv.c | 4 +- source3/nameserv.doc | 50 ++- source3/nameservreply.c | 155 ++++----- source3/nameservreply.doc | 79 ++--- source3/nameservresp.c | 70 ++-- source3/nameservresp.doc | 30 +- source3/smbd/ipc.c | 2 +- 14 files changed, 241 insertions(+), 941 deletions(-) delete mode 100644 source3/namedb.c diff --git a/source3/include/proto.h b/source3/include/proto.h index af5ed8bf41c..2286b93a6d5 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -357,16 +357,18 @@ void add_my_names(void); void remove_my_names(); void refresh_my_names(time_t t); void query_refresh_names(void); -void reply_name_release(struct packet_struct *p); +void add_name_respond(struct subnet_record *d, int fd, uint16 response_id, + struct nmb_name *name, + int nb_flags, int ttl, struct in_addr register_ip, + BOOL new_owner, struct in_addr reply_to_ip); void send_name_response(int fd, int name_trn_id, int opcode, BOOL success, BOOL recurse, struct nmb_name *reply_name, int nb_flags, int ttl, struct in_addr ip); +void reply_name_release(struct packet_struct *p); void reply_name_reg(struct packet_struct *p); void reply_name_status(struct packet_struct *p); void reply_name_query(struct packet_struct *p); -void response_name_release(struct subnet_record *d, struct packet_struct *p); -void response_name_reg(struct subnet_record *d, struct packet_struct *p); void response_netbios_packet(struct packet_struct *p); void reset_server(char *name, int state, struct in_addr ip); void tell_become_backup(void); diff --git a/source3/namedb.c b/source3/namedb.c deleted file mode 100644 index 96f64393c79..00000000000 --- a/source3/namedb.c +++ /dev/null @@ -1,707 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - NBT netbios routines and daemon - version 2 - Copyright (C) Andrew Tridgell 1994-1995 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Revision History: - - 14 jan 96: lkcl@pires.co.uk - added multiple workgroup domain master support - -*/ - -#include "includes.h" -#include "smb.h" - -extern int ClientNMB; -extern int ClientDGRAM; - -extern int DEBUGLEVEL; - -extern time_t StartupTime; -extern pstring myname; -extern pstring scope; - -extern struct in_addr ipgrp; -extern struct in_addr ipzero; - -/* local interfaces structure */ -extern struct interface *local_interfaces; - -/* remote interfaces structure */ -extern struct interface *remote_interfaces; - -/* this is our domain/workgroup/server database */ -struct subnet_record *subnetlist = NULL; - -static BOOL updatedlists = True; -int updatecount=0; - -int workgroup_count = 0; /* unique index key: one for each workgroup */ - -/* what server type are we currently */ - -#define DFLT_SERVER_TYPE (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | \ - SV_TYPE_TIME_SOURCE | SV_TYPE_SERVER_UNIX | \ - SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER) - - -/**************************************************************************** - add a workgroup into the domain list - **************************************************************************/ -static void add_workgroup(struct work_record *work, struct subnet_record *d) -{ - struct work_record *w2; - - if (!work || !d) return; - - if (!d->workgrouplist) - { - d->workgrouplist = work; - work->prev = NULL; - work->next = NULL; - return; - } - - for (w2 = d->workgrouplist; w2->next; w2 = w2->next); - - w2->next = work; - work->next = NULL; - work->prev = w2; -} - - -/**************************************************************************** - create a blank workgroup - **************************************************************************/ -static struct work_record *make_workgroup(char *name) -{ - struct work_record *work; - struct subnet_record *d; - int t = -1; - - if (!name || !name[0]) return NULL; - - work = (struct work_record *)malloc(sizeof(*work)); - if (!work) return(NULL); - - StrnCpy(work->work_group,name,sizeof(work->work_group)-1); - work->serverlist = NULL; - - work->ServerType = DFLT_SERVER_TYPE; - work->RunningElection = False; - work->ElectionCount = 0; - work->needelection = False; - work->needannounce = True; - work->state = MST_NONE; - - /* make sure all token representations of workgroups are unique */ - - for (d = subnetlist; d && t == -1; d = d->next) - { - struct work_record *w; - for (w = d->workgrouplist; w && t == -1; w = w->next) - { - if (strequal(w->work_group, work->work_group)) t = w->token; - } - } - - if (t == -1) - { - work->token = ++workgroup_count; - } - else - { - work->token = t; - } - - - /* WfWg uses 01040b01 */ - /* Win95 uses 01041501 */ - /* NTAS uses ???????? */ - work->ElectionCriterion = (MAINTAIN_LIST<<1)|(ELECTION_VERSION<<8); - work->ElectionCriterion |= (lp_os_level() << 24); - if (lp_domain_master()) { - work->ElectionCriterion |= 0x80; - } - - return work; -} - - -/******************************************************************* - expire old servers in the serverlist - time of -1 indicates everybody dies - ******************************************************************/ -void remove_old_servers(struct work_record *work, time_t t) -{ - struct server_record *s; - struct server_record *nexts; - - /* expire old entries in the serverlist */ - for (s = work->serverlist; s; s = nexts) - { - if (t == -1 || (s->death_time && s->death_time < t)) - { - DEBUG(3,("Removing dead server %s\n",s->serv.name)); - updatedlists = True; - nexts = s->next; - - if (s->prev) s->prev->next = s->next; - if (s->next) s->next->prev = s->prev; - - if (work->serverlist == s) - work->serverlist = s->next; - - free(s); - } - else - { - nexts = s->next; - } - } -} - - -/******************************************************************* - remove workgroups - ******************************************************************/ -struct work_record *remove_workgroup(struct subnet_record *d, - struct work_record *work) -{ - struct work_record *ret_work = NULL; - - if (!d || !work) return NULL; - - DEBUG(3,("Removing old workgroup %s\n", work->work_group)); - - remove_old_servers(work, -1); - - ret_work = work->next; - - if (work->prev) work->prev->next = work->next; - if (work->next) work->next->prev = work->prev; - - if (d->workgrouplist == work) d->workgrouplist = work->next; - - free(work); - - return ret_work; -} - - -/**************************************************************************** - add a domain into the list - **************************************************************************/ -static void add_subnet(struct subnet_record *d) -{ - struct subnet_record *d2; - - if (!subnetlist) - { - subnetlist = d; - d->prev = NULL; - d->next = NULL; - return; - } - - for (d2 = subnetlist; d2->next; d2 = d2->next); - - d2->next = d; - d->next = NULL; - d->prev = d2; -} - -/*************************************************************************** - add a server into the list - **************************************************************************/ -static void add_server(struct work_record *work,struct server_record *s) -{ - struct server_record *s2; - - if (!work->serverlist) { - work->serverlist = s; - s->prev = NULL; - s->next = NULL; - return; - } - - for (s2 = work->serverlist; s2->next; s2 = s2->next) ; - - s2->next = s; - s->next = NULL; - s->prev = s2; -} - - -/**************************************************************************** - find a workgroup in the workgrouplist - only create it if the domain allows it, or the parameter 'add' insists - that it get created/added anyway. this allows us to force entries in - lmhosts file to be added. - **************************************************************************/ -struct work_record *find_workgroupstruct(struct subnet_record *d, - fstring name, BOOL add) -{ - struct work_record *ret, *work; - - if (!d) return NULL; - - DEBUG(4, ("workgroup search for %s: ", name)); - - if (strequal(name, "*")) - { - DEBUG(2,("add any workgroups: initiating browser search on %s\n", - inet_ntoa(d->bcast_ip))); - queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY, NAME_QUERY_FIND_MST, - MSBROWSE,0x1,0,0, - True,False, d->bcast_ip, d->bcast_ip); - return NULL; - } - - for (ret = d->workgrouplist; ret; ret = ret->next) { - if (!strcmp(ret->work_group,name)) { - DEBUG(4, ("found\n")); - return(ret); - } - } - - if (!add) { - DEBUG(4, ("not found\n")); - return NULL; - } - - DEBUG(4,("not found: creating\n")); - - if ((work = make_workgroup(name))) - { - if (lp_preferred_master() && - strequal(lp_workgroup(), name) && - d->my_interface) - { - DEBUG(3, ("preferred master startup for %s\n", work->work_group)); - work->needelection = True; - work->ElectionCriterion |= (1<<3); - } - if (!d->my_interface) - { - work->needelection = False; - } - add_workgroup(work, d); - return(work); - } - return NULL; -} - -/**************************************************************************** - find a subnet in the subnetlist - **************************************************************************/ -struct subnet_record *find_subnet(struct in_addr bcast_ip) -{ - struct subnet_record *d; - struct in_addr wins_ip = ipgrp; - - /* search through subnet list for broadcast/netmask that matches - the source ip address. a subnet 255.255.255.255 represents the - WINS list. */ - - for (d = subnetlist; d; d = d->next) - { - if (ip_equal(bcast_ip, wins_ip)) - { - if (ip_equal(bcast_ip, d->bcast_ip)) - { - return d; - } - } - else if (same_net(bcast_ip, d->bcast_ip, d->mask_ip)) - { - return(d); - } - } - - return (NULL); -} - - -/**************************************************************************** - dump a copy of the workgroup/domain database - **************************************************************************/ -void dump_workgroups(void) -{ - struct subnet_record *d; - - for (d = subnetlist; d; d = d->next) - { - if (d->workgrouplist) - { - struct work_record *work; - - DEBUG(4,("dump domain bcast=%15s: ", inet_ntoa(d->bcast_ip))); - DEBUG(4,(" netmask=%15s:\n", inet_ntoa(d->mask_ip))); - - for (work = d->workgrouplist; work; work = work->next) - { - DEBUG(4,("\t%s(%d)\n", work->work_group, work->token)); - if (work->serverlist) - { - struct server_record *s; - for (s = work->serverlist; s; s = s->next) - { - DEBUG(4,("\t\t%s %8x (%s)\n", - s->serv.name, s->serv.type, s->serv.comment)); - } - } - } - } - } -} - -/**************************************************************************** - create a domain entry - ****************************************************************************/ -static struct subnet_record *make_subnet(struct in_addr bcast_ip, struct in_addr mask_ip) -{ - struct subnet_record *d; - d = (struct subnet_record *)malloc(sizeof(*d)); - - if (!d) return(NULL); - - bzero((char *)d,sizeof(*d)); - - DEBUG(4, ("making domain %s ", inet_ntoa(bcast_ip))); - DEBUG(4, ("%s\n", inet_ntoa(mask_ip))); - - d->bcast_ip = bcast_ip; - d->mask_ip = mask_ip; - d->workgrouplist = NULL; - d->my_interface = False; /* True iff the interface is on the samba host */ - - add_subnet(d); - - return d; -} - - -/**************************************************************************** - add the remote interfaces from lp_remote_interfaces() and lp_interfaces() - to the netbios subnet database. - ****************************************************************************/ -void add_subnet_interfaces(void) -{ - struct interface *i; - - /* loop on all local interfaces */ - for (i = local_interfaces; i; i = i->next) - { - /* add the interface into our subnet database */ - if (!find_subnet(i->bcast)) - { - struct subnet_record *d = make_subnet(i->bcast,i->nmask); - if (d) - { - /* short-cut method to identifying local interfaces */ - d->my_interface = True; - } - } - } - - /* loop on all remote interfaces */ - for (i = remote_interfaces; i; i = i->next) - { - /* add the interface into our subnet database */ - if (!find_subnet(i->bcast)) - { - make_subnet(i->bcast,i->nmask); - } - } - - /* add the pseudo-ip interface for WINS: 255.255.255.255 */ - if (lp_wins_support()) - { - struct in_addr wins_bcast = ipgrp; - struct in_addr wins_nmask = ipzero; - make_subnet(wins_bcast, wins_nmask); - } -} - - -/**************************************************************************** - add a domain entry. creates a workgroup, if necessary, and adds the domain - to the named a workgroup. - ****************************************************************************/ -struct subnet_record *add_subnet_entry(struct in_addr bcast_ip, - struct in_addr mask_ip, - char *name, BOOL add, BOOL lmhosts) -{ - struct subnet_record *d; - - /* XXXX andrew: struct in_addr ip appears not to be referenced at all except - in the DEBUG comment. i assume that the DEBUG comment below actually - intends to refer to bcast_ip? i don't know. - - struct in_addr ip = ipgrp; - - */ - - if (zero_ip(bcast_ip)) - bcast_ip = *iface_bcast(bcast_ip); - - /* add the domain into our domain database */ - if ((d = find_subnet(bcast_ip)) || - (d = make_subnet(bcast_ip, mask_ip))) - { - struct work_record *w = find_workgroupstruct(d, name, add); - extern pstring ServerComment; - - if (!w) return NULL; - - /* add WORKGROUP(1e) and WORKGROUP(00) entries into name database - or register with WINS server, if it's our workgroup */ - if (strequal(lp_workgroup(), name) && d->my_interface) - { - add_my_name_entry(d,name,0x1e,NB_ACTIVE|NB_GROUP); - add_my_name_entry(d,name,0x0 ,NB_ACTIVE|NB_GROUP); - } - /* add samba server name to workgroup list */ - if ((strequal(lp_workgroup(), name) && d->my_interface) || lmhosts) - { - add_server_entry(d,w,myname,w->ServerType,0,ServerComment,True); - } - - DEBUG(3,("Added domain name entry %s at %s\n", name,inet_ntoa(bcast_ip))); - return d; - } - return NULL; -} - -/**************************************************************************** - 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); - } - } - } -} - - -/**************************************************************************** - add a server entry - ****************************************************************************/ -struct server_record *add_server_entry(struct subnet_record *d, - struct work_record *work, - char *name,int servertype, - int ttl,char *comment, - BOOL replace) -{ - BOOL newentry=False; - struct server_record *s; - - if (name[0] == '*') - { - return (NULL); - } - - for (s = work->serverlist; s; s = s->next) - { - if (strequal(name,s->serv.name)) break; - } - - if (s && !replace) - { - DEBUG(4,("Not replacing %s\n",name)); - return(s); - } - - if (!s || s->serv.type != servertype || !strequal(s->serv.comment, comment)) - updatedlists=True; - - if (!s) - { - newentry = True; - s = (struct server_record *)malloc(sizeof(*s)); - - if (!s) return(NULL); - - bzero((char *)s,sizeof(*s)); - } - - - if (d->my_interface && strequal(lp_workgroup(),work->work_group)) - { - if (servertype) - servertype |= SV_TYPE_LOCAL_LIST_ONLY; - } - else - { - servertype &= ~SV_TYPE_LOCAL_LIST_ONLY; - } - - /* update the entry */ - StrnCpy(s->serv.name,name,sizeof(s->serv.name)-1); - StrnCpy(s->serv.comment,comment,sizeof(s->serv.comment)-1); - strupper(s->serv.name); - s->serv.type = servertype; - s->death_time = servertype ? (ttl?time(NULL)+ttl*3:0) : (time(NULL)-1); - - /* for a domain entry, the comment field refers to the server name */ - - if (s->serv.type & SV_TYPE_DOMAIN_ENUM) strupper(s->serv.comment); - - if (newentry) - { - add_server(work, s); - - DEBUG(3,("Added ")); - } - else - { - DEBUG(3,("Updated ")); - } - - DEBUG(3,("server entry %s of type %x (%s) to %s %s\n", - name,servertype,comment, - work->work_group,inet_ntoa(d->bcast_ip))); - - return(s); -} - - -/**************************************************************************** - add the default workgroup into my domain - **************************************************************************/ -void add_my_subnets(char *group) -{ - struct interface *i; - - /* add or find domain on our local subnet, in the default workgroup */ - - if (*group == '*') return; - - /* the coding choice is up to you, andrew: i can see why you don't want - global access to the local_interfaces structure: so it can't get - messed up! */ - for (i = local_interfaces; i; i = i->next) - { - add_subnet_entry(i->bcast,i->nmask,group, True, False); - } -} - - -/******************************************************************* - write out browse.dat - ******************************************************************/ -void write_browse_list(void) -{ - struct subnet_record *d; - - pstring fname,fnamenew; - FILE *f; - - if (!updatedlists) return; - - dump_names(); - dump_workgroups(); - - updatedlists = False; - updatecount++; - - strcpy(fname,lp_lockdir()); - trim_string(fname,NULL,"/"); - strcat(fname,"/"); - strcat(fname,SERVER_LIST); - strcpy(fnamenew,fname); - strcat(fnamenew,"."); - - f = fopen(fnamenew,"w"); - - if (!f) - { - DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno))); - return; - } - - 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) - { - fstring tmp; - - /* don't list domains I don't have a master for */ - if ((s->serv.type & SV_TYPE_DOMAIN_ENUM) && !s->serv.comment[0]) - { - continue; - } - - /* output server details, plus what workgroup/domain - they're in. without the domain information, the - combined list of all servers in all workgroups gets - sent to anyone asking about any workgroup! */ - - sprintf(tmp, "\"%s\"", s->serv.name); - fprintf(f, "%-25s ", tmp); - fprintf(f, "%08x ", s->serv.type); - sprintf(tmp, "\"%s\" ", s->serv.comment); - fprintf(f, "%-30s", tmp); - fprintf(f, "\"%s\"\n", work->work_group); - } - } - } - - fclose(f); - unlink(fname); - chmod(fnamenew,0644); - rename(fnamenew,fname); - DEBUG(3,("Wrote browse list %s\n",fname)); -} - - -/******************************************************************* - expire old servers in the serverlist - ******************************************************************/ -void expire_servers(time_t t) -{ - struct subnet_record *d; - - for (d = subnetlist ; d ; d = d->next) - { - struct work_record *work; - - for (work = d->workgrouplist; work; work = work->next) - { - remove_old_servers(work, t); - } - } -} - diff --git a/source3/namedbresp.doc b/source3/namedbresp.doc index 68db43aec2a..66f5a22124f 100644 --- a/source3/namedbresp.doc +++ b/source3/namedbresp.doc @@ -22,7 +22,7 @@ the response to come from. 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. +the number of retries is set to 3, 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. diff --git a/source3/namedbsubnet.c b/source3/namedbsubnet.c index 6b187b21bb8..dd26592e66b 100644 --- a/source3/namedbsubnet.c +++ b/source3/namedbsubnet.c @@ -253,13 +253,16 @@ struct subnet_record *add_subnet_entry(struct in_addr bcast_ip, add_my_name_entry(d,name,0x1e,NB_ACTIVE|NB_GROUP); add_my_name_entry(d,name,0x0 ,NB_ACTIVE|NB_GROUP); } - /* add samba server name to workgroup list */ - if ((strequal(lp_workgroup(), name) && d->my_interface) || lmhosts) + /* add samba server name to workgroup list. don't add + lmhosts server entries to local interfaces */ + if ((strequal(lp_workgroup(), name) && d->my_interface) || + (lmhosts && !d->my_interface)) { add_server_entry(d,w,myname,w->ServerType,0,ServerComment,True); + DEBUG(3,("Added server name entry %s at %s\n", + name,inet_ntoa(bcast_ip))); } - DEBUG(3,("Added domain name entry %s at %s\n", name,inet_ntoa(bcast_ip))); return d; } return NULL; diff --git a/source3/nameelect.c b/source3/nameelect.c index e115b0d8818..ba66f41a916 100644 --- a/source3/nameelect.c +++ b/source3/nameelect.c @@ -255,6 +255,7 @@ void become_master(struct subnet_record *d, struct work_record *work) { case MST_NONE: /* while we were nothing but a server... */ { + DEBUG(3,("go to first stage: register ^1^2__MSBROWSE__^2^1\n")); work->state = MST_WON; /* ... an election win was successful */ work->ElectionCriterion |= 0x5; @@ -263,29 +264,29 @@ void become_master(struct subnet_record *d, struct work_record *work) work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER; add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True); - DEBUG(3,("go to first stage: register ^1^2__MSBROWSE__^2^1\n")); - /* add special browser name */ add_my_name_entry(d,MSBROWSE ,0x01,NB_ACTIVE|NB_GROUP); - break; + /* DON'T do anything else after calling add_my_name_entry() */ + return; } case MST_WON: /* while nothing had happened except we won an election... */ { + DEBUG(3,("go to second stage: register as master browser\n")); 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); - DEBUG(3,("go to second stage: register as master browser\n")); - /* add master name */ add_my_name_entry(d,work->work_group,0x1d,NB_ACTIVE ); - break; + /* DON'T do anything else after calling add_my_name_entry() */ + return; } case MST_MSB: /* while we were still only registered MSBROWSE state... */ { + DEBUG(3,("2nd stage complete: registered as master browser\n")); work->state = MST_BROWSER; /* ... registering WORKGROUP(1d) succeeded */ /* update our server status */ @@ -301,8 +302,12 @@ void become_master(struct subnet_record *d, struct work_record *work) if (lp_domain_master()) { DEBUG(3,("third stage: register as domain master\n")); + /* add domain master name */ add_my_name_entry(d,work->work_group,0x1b,NB_ACTIVE ); + + /* DON'T do anything else after calling add_my_name_entry() */ + return; } else { @@ -313,11 +318,12 @@ void become_master(struct subnet_record *d, struct work_record *work) } case MST_BROWSER: /* while we were still a master browser... */ { - work->state = MST_DOMAIN; /* ... registering WORKGROUP(1b) succeeded */ - /* update our server status */ if (lp_domain_master()) { + DEBUG(3,("fourth stage: samba is now a domain master.\n")); + work->state = MST_DOMAIN; /* ... registering WORKGROUP(1b) succeeded */ + work->ServerType |= SV_TYPE_DOMAIN_MASTER; if (lp_domain_logons()) @@ -325,7 +331,6 @@ void become_master(struct subnet_record *d, struct work_record *work) work->ServerType |= SV_TYPE_DOMAIN_CTRL; work->ServerType |= SV_TYPE_DOMAIN_MEMBER; } - DEBUG(3,("fourth stage: samba is now a domain master.\n")); add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True); } diff --git a/source3/nameelect.doc b/source3/nameelect.doc index b8e6b56ad9c..c03f044541c 100644 --- a/source3/nameelect.doc +++ b/source3/nameelect.doc @@ -180,10 +180,17 @@ 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. +if it's a local subnet and not one of samba's workgroups, then +samba will force an election (which it is not obliged to do). +remove_workgroup() will be expected to remove all references +to this workgroup and the servers in it from the database. + +if it's a remote subnet and not one of samba's workgroups then +no election is forced, and remove_workgroup() will be expected +to remove all server entries from this workgroup _except_ those +added from the lmhosts file. if there are entries added from +the lmhosts file, then the workgroup entry will remain, +otherwise it too will be removed. /************************************************************************* diff --git a/source3/nameresp.c b/source3/nameresp.c index 3a9d46bf9d8..f87088dffa5 100644 --- a/source3/nameresp.c +++ b/source3/nameresp.c @@ -113,15 +113,18 @@ static void dead_netbios_entry(struct subnet_record *d, 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); + add_name_respond(d,n->fd, n->response_id ,&n->name, + n->nb_flags, GET_TTL(0), + n->reply_to_ip, False, n->reply_to_ip); - 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; + if (!n->bcast) + { + DEBUG(1,("WINS server did not respond to name registration!\n")); + /* XXXX whoops. we have problems. must deal with this */ + } + break; } + case NAME_REGISTER: { /* if no response received, and we are using a broadcast registration @@ -141,14 +144,13 @@ static void dead_netbios_entry(struct subnet_record *d, } else { - /* XXXX oops. this is where i wish this code could retry DGRAM - packets. we directed a name registration at a WINS server, and - received no response. rfc1001.txt states that after retrying, + /* received no response. rfc1001.txt states that after retrying, we should assume the WINS server is dead, and fall back to - broadcasting. */ + broadcasting (see bits about M nodes: can't find any right + now) */ - DEBUG(1,("WINS server did not respond to name registration!\n")); - /* XXXX whoops. we have problems. must deal with this */ + DEBUG(1,("WINS server did not respond to name registration!\n")); + /* XXXX whoops. we have problems. must deal with this */ } break; } diff --git a/source3/nameserv.c b/source3/nameserv.c index 9fc578d009f..371f12e0110 100644 --- a/source3/nameserv.c +++ b/source3/nameserv.c @@ -141,8 +141,8 @@ void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags) actually be true */ - add_netbios_entry(d,name,type,nb_flags,0, - SELF,ipzero,False,lp_wins_support()); + /* this will call add_netbios_entry() */ + name_register_work(d, name, type, nb_flags,0, ipzero, False); } else { diff --git a/source3/nameserv.doc b/source3/nameserv.doc index 8cb2bbc53dc..71e5c980c69 100644 --- a/source3/nameserv.doc +++ b/source3/nameserv.doc @@ -62,12 +62,33 @@ if samba is using one. if the name is already in samba's database, then it is re-registered, otherwise it is simply registered. -if samba registers its name with another WINS server, then the function -response_name_reg() is responsible for updating samba's name database -to reflect the claim or otherwise of the name. +if the name is being registered in a WINS capacity (the subnet to which +the name should be added is the WINS pseudo-subnet) then we add the entry +immediately if samba is a WINS server. it uses name_register_work() +because if the name is being added as part of becoming a master browser, +we want to carry on that process. if the name is registered with another +WINS server, we must wait for an answer from that WINS server. either +name_register_work() or name_unregister_work() will be called as a result. -expire_netbios_response_entries() is responsible for taking further action -if no response to the registration is received. +if the name is being registered on a local subnet, then it is +broadcast. an explicit rejection from another host will result +in name_unregister_work() being called. no response will, after +retrying, result in name_register_work() being called. + +what ever method is used, the name will either be registered +or rejected, and what ever process was taking place (becoming +a master browser for example) will carry on. + +expire_netbios_response_entries() is responsible for taking further +action if no response to the registration is received. + +note that there may be a large number of function calls on the +stack if become_master() is called and samba is configured as +a WINS server. the loop will be: + +become_master(), add_my_name_entry(), name_register_work() and +back to become_master() with the new value of the workgroup +'state'. /************************************************************************* @@ -78,9 +99,22 @@ this function is responsible for removing a NetBIOS name. if the name being removed is registered on a local subnet, a name release should be broadcast on the local subnet. -if samba has registered the name with a WINS server, it must send a -name release to the WINS server it is using. once it receives a reply, -it can proceed (see response_name_rel()) +if the name is being released in a WINS capacity (the subnet to +which the name should be added is the WINS pseudo-subnet) then we +remove the entry immediately if samba is a WINS server. it uses +name_unregister_work() because if the name is being added as part of +becoming a master browser, we want to terminate that process. if the +name is released from another WINS server, we must wait for an +answer from that WINS server. name_unregister_work() will +definitely be called as a result, because at present we ignore +negative responses for a name release from a WINS server. + +if the name is being releasedd on a local subnet, then it is +broadcast. name_unregister_work() will definitely be called +because we ignore negative name releases at present. + +what ever method is used, the name will be released. (NOT TRUE! +see response_name_release()) expire_netbios_response_entries() is responsible for taking further action if no response to the name release is received. diff --git a/source3/nameservreply.c b/source3/nameservreply.c index cd26be5a8b2..6501bded685 100644 --- a/source3/nameservreply.c +++ b/source3/nameservreply.c @@ -40,56 +40,23 @@ extern struct in_addr ipgrp; /**************************************************************************** -reply to a name release -****************************************************************************/ -void reply_name_release(struct packet_struct *p) + add a netbios entry. respond to the (possibly new) owner. + **************************************************************************/ +void add_name_respond(struct subnet_record *d, int fd, uint16 response_id, + struct nmb_name *name, + int nb_flags, int ttl, struct in_addr register_ip, + BOOL new_owner, struct in_addr reply_to_ip) { - struct nmb_packet *nmb = &p->packet.nmb; - struct in_addr ip; - int nb_flags = nmb->additional->rdata[0]; - BOOL bcast = nmb->header.nm_flags.bcast; - struct name_record *n; - struct subnet_record *d = NULL; - int search = 0; - - putip((char *)&ip,&nmb->additional->rdata[2]); - - DEBUG(3,("Name release on name %s\n", - namestr(&nmb->question.question_name))); - - if (!(d = find_req_subnet(p->ip, bcast))) - { - DEBUG(3,("response packet: bcast %s not known\n", - inet_ntoa(p->ip))); - return; - } - - if (bcast) - search &= FIND_LOCAL; - else - search &= FIND_WINS; - - n = find_name_search(&d, &nmb->question.question_name, - search, ip); - - /* XXXX under what conditions should we reject the removal?? */ - if (n && n->nb_flags == nb_flags) - { - /* success = True; */ - - remove_name(d,n); - n = NULL; - } - - if (bcast) return; - - /* Send a NAME RELEASE RESPONSE */ - send_name_response(p->fd, nmb->header.name_trn_id, NMB_REL, - True, False, - &nmb->question.question_name, nb_flags, 0, ip); + /* register the old or the new owners' ip */ + add_netbios_entry(d,name->name,name->name_type, + nb_flags,ttl,REGISTER,register_ip,False,True); + + /* reply yes or no to the host that requested the name */ + send_name_response(fd, response_id, NMB_REG, + new_owner, True, + name, nb_flags, ttl, reply_to_ip); } - /**************************************************************************** send a registration / release response: pos/neg **************************************************************************/ @@ -132,6 +99,58 @@ void send_name_response(int fd, } +/**************************************************************************** +reply to a name release +****************************************************************************/ +void reply_name_release(struct packet_struct *p) +{ + struct nmb_packet *nmb = &p->packet.nmb; + struct in_addr ip; + int nb_flags = nmb->additional->rdata[0]; + BOOL bcast = nmb->header.nm_flags.bcast; + struct name_record *n; + struct subnet_record *d = NULL; + int search = 0; + BOOL success = False; + + putip((char *)&ip,&nmb->additional->rdata[2]); + + DEBUG(3,("Name release on name %s\n", + namestr(&nmb->question.question_name))); + + if (!(d = find_req_subnet(p->ip, bcast))) + { + DEBUG(3,("response packet: bcast %s not known\n", + inet_ntoa(p->ip))); + return; + } + + if (bcast) + search &= FIND_LOCAL; + else + search &= FIND_WINS; + + n = find_name_search(&d, &nmb->question.question_name, + search, ip); + + /* XXXX under what conditions should we reject the removal?? */ + if (n && n->nb_flags == nb_flags) + { + success = True; + + remove_name(d,n); + n = NULL; + } + + if (bcast) return; + + /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */ + send_name_response(p->fd, nmb->header.name_trn_id, NMB_REL, + success, False, + &nmb->question.question_name, nb_flags, 0, ip); +} + + /**************************************************************************** reply to a reg request **************************************************************************/ @@ -156,10 +175,6 @@ void reply_name_reg(struct packet_struct *p) BOOL success = True; BOOL secured_redirect = False; - BOOL recurse = True; /* true if samba replies yes/no: false if caller - must challenge the current owner of the unique - name: applies to non-secured WINS server only - */ struct in_addr ip, from_ip; int search = 0; @@ -205,38 +220,6 @@ void reply_name_reg(struct packet_struct *p) } else if(!ip_equal(ip, n->ip)) { -#if 0 - /* hm. this unique name doesn't belong to them. */ - - /* XXXX rfc1001.txt says: - * if we are doing non-secured WINS (which is much simpler) then - * we send a message to the person wanting the name saying 'he - * owns this name: i don't want to hear from you ever again - * until you've checked with him if you can have it!'. we then - * abandon the registration. once the person wanting the name - * has checked with the current owner, they will repeat the - * registration packet if the current owner is dead or doesn't - * want the name. - */ - - /* non-secured WINS implementation: caller is responsible - for checking with current owner of name, then getting back - to us... IF current owner no longer owns the unique name */ - - /* XXXX please note also that samba cannot cope with - _receiving_ such redirecting, non-secured registration - packets. code to do this needs to be added. - */ - - secured_redirect = False; - success = False; - recurse = False; - - /* we inform on the current owner to the caller (which is - why it's non-secure */ - - reply_name = &n->name; -#else /* XXXX rfc1001.txt says: * if we are doing secured WINS, we must send a Wait-Acknowledge * packet (WACK) to the person who wants the name, then do a @@ -246,12 +229,8 @@ void reply_name_reg(struct packet_struct *p) */ secured_redirect = True; - recurse = False; reply_name = &n->name; - -#endif /* 0 */ - } else { @@ -324,7 +303,7 @@ void reply_name_reg(struct packet_struct *p) */ send_name_response(p->fd, nmb->header.name_trn_id, NMB_REG, - success, recurse, + success, True, reply_name, nb_flags, ttl, ip); } } diff --git a/source3/nameservreply.doc b/source3/nameservreply.doc index aeb3d29f17a..56a5d160f6a 100644 --- a/source3/nameservreply.doc +++ b/source3/nameservreply.doc @@ -26,13 +26,15 @@ 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. +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 packet -received is a point-to-point (unicast), then the WINS database -is included in the search. +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 search is not in the WINS database, then we need to find the +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. @@ -100,7 +102,8 @@ 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. +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 @@ -116,53 +119,20 @@ 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 +name registrations by broadcast is implicit), samba will send either 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. - +REGISTRATION RESPONSE 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() *************************************************************************/ @@ -187,3 +157,30 @@ 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. + +/************************************************************************* + send_name_response() + *************************************************************************/ + +this function is a wrap around reply_netbios_packet(). it sends +a response to a name registration or release packet, minimising +the function parameters needed to do this. + +if the function is called with the parameter 'success' set to +True, then a positive response (to the registration or release) +is made (see rfc1002.txt 4.2.5 and 4.2.10). if this parameter +is False, then a negative response is issued (see rfc1002.txt +4.2.6 and 4.2.11) + +if the function is called with a registration code, and the +parameter 'recurse' is False, then an End-Node Challenge +Registration response is issued (see rfc1002.txt 4.2.7) + +note: this function could also easily be used for name conflict +demand (see rfc1002.txt 4.2.8). + +note: End-Node Challenge Registration response is only sent in +non-secured NetBIOS Name Server implementations. samba now +implements secured NetBIOS Name Server functionality (see +rfc1001.txt 15.1.6). + diff --git a/source3/nameservresp.c b/source3/nameservresp.c index dc7cc63c5ac..e47afc55b34 100644 --- a/source3/nameservresp.c +++ b/source3/nameservresp.c @@ -46,7 +46,8 @@ extern struct in_addr ipzero; response for a reg release received. samba has asked a WINS server if it could release a name. **************************************************************************/ -void response_name_release(struct subnet_record *d, struct packet_struct *p) +static void response_name_release(struct subnet_record *d, + struct packet_struct *p) { struct nmb_packet *nmb = &p->packet.nmb; char *name = nmb->question.question_name.name; @@ -55,33 +56,42 @@ void response_name_release(struct subnet_record *d, struct packet_struct *p) DEBUG(4,("response name release received\n")); if (nmb->header.rcode == 0 && nmb->answers->rdata) - { - /* IMPORTANT: see expire_netbios_response_entries() */ + { + /* IMPORTANT: see expire_netbios_response_entries() */ - struct in_addr found_ip; - putip((char*)&found_ip,&nmb->answers->rdata[2]); + struct in_addr found_ip; + putip((char*)&found_ip,&nmb->answers->rdata[2]); - if (ismyip(found_ip)) - { - remove_netbios_name(d,name,type,SELF,found_ip); - } + /* NOTE: we only release our own names at present */ + if (ismyip(found_ip)) + { + name_unregister_work(d,name,type); } - else + else { - DEBUG(2,("name release for %s rejected!\n", + DEBUG(2,("name release for different ip! %s %s\n", + inet_ntoa(found_ip), + namestr(&nmb->question.question_name))); + } + } + else + { + DEBUG(2,("name release for %s rejected!\n", namestr(&nmb->question.question_name))); - /* XXXX do we honestly care if our name release was rejected? - only if samba is issuing the release on behalf of some out-of-sync - server. if it's one of samba's SELF names, we don't care. */ - } + /* XXXX PANIC! what to do if it's one of samba's own names? */ + + /* XXXX do we honestly care if our name release was rejected? + only if samba is issuing the release on behalf of some out-of-sync + server. if it's one of samba's SELF names, we don't care. */ + } } /**************************************************************************** response for a reg request received **************************************************************************/ -void response_name_reg(struct subnet_record *d, struct packet_struct *p) +static void response_name_reg(struct subnet_record *d, struct packet_struct *p) { struct nmb_packet *nmb = &p->packet.nmb; char *name = nmb->question.question_name.name; @@ -92,25 +102,22 @@ void response_name_reg(struct subnet_record *d, struct packet_struct *p) if (nmb->header.rcode == 0 && nmb->answers->rdata) { - /* IMPORTANT: see expire_netbios_response_entries() */ + /* IMPORTANT: see expire_netbios_response_entries() */ - int nb_flags = nmb->answers->rdata[0]; - int ttl = nmb->answers->ttl; - struct in_addr found_ip; + int nb_flags = nmb->answers->rdata[0]; + int ttl = nmb->answers->ttl; + struct in_addr found_ip; - putip((char*)&found_ip,&nmb->answers->rdata[2]); + putip((char*)&found_ip,&nmb->answers->rdata[2]); - name_register_work(d,name,type,nb_flags,ttl,found_ip,bcast); + name_register_work(d,name,type,nb_flags,ttl,found_ip,bcast); } else { DEBUG(1,("name registration for %s rejected!\n", namestr(&nmb->question.question_name))); - /* XXXX oh dear. we have problems. must deal with our name having - been rejected: e.g if it was our GROUP(1d) name, we must unbecome - a master browser. */ - + /* oh dear. we have problems. possibly unbecome a master browser. */ name_unregister_work(d,name,type); } } @@ -332,14 +339,9 @@ static void response_name_query_register(struct nmb_packet *nmb, } /* register the old or the new owners' ip */ - add_netbios_entry(d, ans_name->name, ans_name->name_type, - n->nb_flags,GET_TTL(0),REGISTER, - register_ip,False,True); - - /* reply yes or no to the host that requested the name */ - send_name_response(n->fd, n->response_id, NMB_REG, - new_owner, True, - &n->name, n->nb_flags, GET_TTL(0), n->reply_to_ip); + add_name_respond(d, n->fd, n->response_id,&n->name,n->nb_flags, + GET_TTL(0), register_ip, + new_owner, n->reply_to_ip); } diff --git a/source3/nameservresp.doc b/source3/nameservresp.doc index 2f0d1912c89..f50f3a7c4f1 100644 --- a/source3/nameservresp.doc +++ b/source3/nameservresp.doc @@ -2,6 +2,9 @@ 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) +point of interest to design purists: every function in this +module is static except response_netbios_packet(). + /************************************************************************* response_netbios_packet() *************************************************************************/ @@ -61,33 +64,6 @@ 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() *************************************************************************/ diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c index 415c939bf38..0f00e3ec21d 100644 --- a/source3/smbd/ipc.c +++ b/source3/smbd/ipc.c @@ -1013,7 +1013,7 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data, int counted=0,total=0; int i; fstring domain; - BOOL domains; + BOOL domains = False; BOOL domain_request; BOOL local_request = servertype & SV_TYPE_LOCAL_LIST_ONLY; -- 2.34.1