diff options
-rw-r--r-- | source3/include/proto.h | 8 | ||||
-rw-r--r-- | source3/namedb.c | 707 | ||||
-rw-r--r-- | source3/namedbresp.doc | 2 | ||||
-rw-r--r-- | source3/namedbsubnet.c | 9 | ||||
-rw-r--r-- | source3/nameelect.c | 23 | ||||
-rw-r--r-- | source3/nameelect.doc | 15 | ||||
-rw-r--r-- | source3/nameresp.c | 28 | ||||
-rw-r--r-- | source3/nameserv.c | 4 | ||||
-rw-r--r-- | source3/nameserv.doc | 50 | ||||
-rw-r--r-- | source3/nameservreply.c | 155 | ||||
-rw-r--r-- | source3/nameservreply.doc | 79 | ||||
-rw-r--r-- | source3/nameservresp.c | 70 | ||||
-rw-r--r-- | source3/nameservresp.doc | 30 | ||||
-rw-r--r-- | source3/smbd/ipc.c | 2 |
14 files changed, 241 insertions, 941 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h index af5ed8bf41..2286b93a6d 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 96f64393c7..0000000000 --- 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 68db43aec2..66f5a22124 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 6b187b21bb..dd26592e66 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 e115b0d881..ba66f41a91 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 b8e6b56ad9..c03f044541 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 3a9d46bf9d..f87088dffa 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 9fc578d009..371f12e011 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 8cb2bbc53d..71e5c980c6 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 cd26be5a8b..6501bded68 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 **************************************************************************/ @@ -133,6 +100,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 **************************************************************************/ void reply_name_reg(struct packet_struct *p) @@ -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 aeb3d29f17..56a5d160f6 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,54 +119,21 @@ 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 dc7cc63c5a..e47afc55b3 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 2f0d1912c8..f50f3a7c4f 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() *************************************************************************/ @@ -62,33 +65,6 @@ 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 415c939bf3..0f00e3ec21 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; |