diff options
Diffstat (limited to 'source3/nameserv.c')
-rw-r--r-- | source3/nameserv.c | 2318 |
1 files changed, 0 insertions, 2318 deletions
diff --git a/source3/nameserv.c b/source3/nameserv.c deleted file mode 100644 index 802b98ec0a..0000000000 --- a/source3/nameserv.c +++ /dev/null @@ -1,2318 +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. - -*/ - -#include "includes.h" -#include "loadparm.h" -#include "nameserv.h" - - -static void queue_packet(struct packet_struct *packet); -void process(void); -static void dump_names(void); -static void announce_request(char *group); -void sync_browse_lists(char *name,int name_type,char *myname, - char *domain,struct in_addr ip); - -extern int DEBUGLEVEL; - -extern pstring debugf; -pstring servicesf = CONFIGFILE; - -extern pstring scope; - -extern BOOL CanRecurse; - -extern struct in_addr myip; -extern struct in_addr bcast_ip; -extern struct in_addr Netmask; -extern pstring myhostname; -static pstring host_file; -static pstring myname=""; - -static int ClientNMB= -1; -static int ClientDGRAM= -1; - -static BOOL needannounce=True; - -/* this is our name database */ -static struct name_record *namelist = NULL; - -/* list of servers to be returned by NetServerEnum */ -static struct server_record *serverlist = NULL; - -/* this is the domain list. For the moment we will assume that our - primary domain is the first one listed in this list */ -static struct domain_record *domainlist = NULL; - -/* are we running as a daemon ? */ -static BOOL is_daemon = False; - -/* machine comment for host announcements */ -static pstring ServerComment=""; - -static BOOL got_bcast = False; -static BOOL got_myip = False; -static BOOL got_nmask = False; - -static BOOL updatedlists = False; -static int updatecount=0; - -/* what server type are we currently */ -static int ServerType = -SV_TYPE_WORKSTATION | SV_TYPE_SERVER | SV_TYPE_TIME_SOURCE | -SV_TYPE_SERVER_UNIX | -SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER; - -/* here are my election parameters */ - -/* NTAS uses 2, NT uses 1, WfWg uses 0 */ -#define MAINTAIN_LIST 1 -#define ELECTION_VERSION 1 - -static BOOL RunningElection = False; -static BOOL needelection = False; -static int ElectionCount = 0; -static int StartupTime =0; - - -/* WfWg uses 01040b01 */ -/* Win95 uses 01041501 */ -/* NTAS uses ?? */ -static uint32 ElectionCriterion = (MAINTAIN_LIST<<1)|(ELECTION_VERSION<<8); - -/* we currently support being the master for just one group. Being the - master for more than one group might be tricky as NetServerEnum is - often asked for a list without naming the group */ -static fstring PrimaryGroup=""; - -#define AM_MASTER (PrimaryGroup[0] && (ServerType & SV_TYPE_MASTER_BROWSER)) - -#define MSBROWSE "\001\002__MSBROWSE__\002" - -#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl()) - -#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE" - -/**************************************************************************** -catch a sighup -****************************************************************************/ -static int sig_hup() -{ - BlockSignals(True); - - DEBUG(0,("Got SIGHUP (reload not implemented)\n")); - dump_names(); - reload_services(True); - - BlockSignals(False); -#ifndef DONT_REINSTALL_SIG - signal(SIGHUP,SIGNAL_CAST sig_hup); -#endif - return(0); -} - -/**************************************************************************** -catch a sigpipe -****************************************************************************/ -static int sig_pipe() -{ - BlockSignals(True); - - DEBUG(0,("Got SIGPIPE\n")); - if (!is_daemon) - exit(1); - BlockSignals(False); - return(0); -} - -#if DUMP_CORE -/******************************************************************* -prepare to dump a core file - carefully! -********************************************************************/ -static BOOL dump_core(void) -{ - char *p; - pstring dname; - strcpy(dname,debugf); - if ((p=strrchr(dname,'/'))) *p=0; - strcat(dname,"/corefiles"); - mkdir(dname,0700); - sys_chown(dname,getuid(),getgid()); - chmod(dname,0700); - if (chdir(dname)) return(False); - umask(~(0700)); - -#ifndef NO_GETRLIMIT -#ifdef RLIMIT_CORE - { - struct rlimit rlp; - getrlimit(RLIMIT_CORE, &rlp); - rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur); - setrlimit(RLIMIT_CORE, &rlp); - getrlimit(RLIMIT_CORE, &rlp); - DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max)); - } -#endif -#endif - - - DEBUG(0,("Dumping core in %s\n",dname)); - return(True); -} -#endif - - -/**************************************************************************** -possibly continue after a fault -****************************************************************************/ -static void fault_continue(void) -{ - static int errcount=1; - - errcount--; - - if (is_daemon && errcount) - process(); - -#if DUMP_CORE - if (dump_core()) return; -#endif - - return; -} - - -/******************************************************************* - wrapper to get the DC - ******************************************************************/ -static char *domain_controller(void) -{ - char *dc = lp_domain_controller(); - /* so many people mistake this for a bool that we need to handle it. sigh. */ - if (!*dc || strequal(dc,"yes") || strequal(dc,"true")) - strcpy(dc,myname); - return(dc); -} - - - -/**************************************************************************** - true if two netbios names are equal -****************************************************************************/ -static BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2) -{ - if (n1->name_type != n2->name_type) return(False); - - return(strequal(n1->name,n2->name) && strequal(n1->scope,n2->scope)); -} - -/**************************************************************************** - add a netbios name into the namelist - **************************************************************************/ -static void add_name(struct name_record *n) -{ - struct name_record *n2; - - if (!namelist) { - namelist = n; - n->prev = NULL; - n->next = NULL; - return; - } - - for (n2 = namelist; n2->next; n2 = n2->next) ; - - n2->next = n; - n->next = NULL; - n->prev = n2; -} - -/**************************************************************************** - add a domain into the list - **************************************************************************/ -static void add_domain(struct domain_record *d) -{ - struct domain_record *d2; - - if (!domainlist) { - domainlist = d; - d->prev = NULL; - d->next = NULL; - return; - } - - for (d2 = domainlist; 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 server_record *s) -{ - struct server_record *s2; - - if (!serverlist) { - serverlist = s; - s->prev = NULL; - s->next = NULL; - return; - } - - for (s2 = serverlist; s2->next; s2 = s2->next) ; - - s2->next = s; - s->next = NULL; - s->prev = s2; -} - -/**************************************************************************** - remove a name from the namelist. The pointer must be an element just - retrieved - **************************************************************************/ -static void remove_name(struct name_record *n) -{ - struct name_record *nlist = namelist; - while (nlist && nlist != n) nlist = nlist->next; - if (nlist) { - if (nlist->next) nlist->next->prev = nlist->prev; - if (nlist->prev) nlist->prev->next = nlist->next; - free(nlist); - } -} - -/**************************************************************************** - find a name in the namelist - **************************************************************************/ -static struct name_record *find_name(struct nmb_name *n) -{ - struct name_record *ret; - for (ret = namelist; ret; ret = ret->next) - if (name_equal(&ret->name,n)) return(ret); - - return(NULL); -} - -/**************************************************************************** - dump a copy of the name table - **************************************************************************/ -static void dump_names(void) -{ - time_t t = time(NULL); - struct name_record *n; - struct domain_record *d; - - DEBUG(3,("Dump of local name table:\n")); - - for (n = namelist; n; n = n->next) { - DEBUG(3,("%s %s TTL=%d Unique=%s\n", - namestr(&n->name), - inet_ntoa(n->ip), - n->death_time?n->death_time-t:0, - BOOLSTR(n->unique))); - } - - DEBUG(3,("\nDump of domain list:\n")); - for (d = domainlist; d; d = d->next) - DEBUG(3,("%s %s\n",d->name,inet_ntoa(d->bcast_ip))); -} - - -/**************************************************************************** - add a host entry to the name list - ****************************************************************************/ -static struct name_record *add_host_entry(char *name,int type,BOOL unique,int ttl, - enum name_source source, - struct in_addr ip) -{ - struct name_record *n; - struct name_record *n2=NULL; - - n = (struct name_record *)malloc(sizeof(*n)); - if (!n) return(NULL); - - bzero((char *)n,sizeof(*n)); - - make_nmb_name(&n->name,name,type,scope); - if ((n2=find_name(&n->name))) { - free(n); - n = n2; - } - - if (ttl) n->death_time = time(NULL)+ttl*3; - n->ip = ip; - n->unique = unique; - n->source = source; - - if (!n2) add_name(n); - - DEBUG(3,("Added host entry %s at %s ttl=%d unique=%s\n", - namestr(&n->name),inet_ntoa(ip),ttl,BOOLSTR(unique))); - - return(n); -} - - -/**************************************************************************** - add a domain entry - ****************************************************************************/ -static struct domain_record *add_domain_entry(char *name,struct in_addr ip) -{ - struct domain_record *d; - - d = (struct domain_record *)malloc(sizeof(*d)); - - if (!d) return(NULL); - - bzero((char *)d,sizeof(*d)); - - if (zero_ip(ip)) ip = bcast_ip; - - StrnCpy(d->name,name,sizeof(d->name)-1); - d->bcast_ip = ip; - - if (!PrimaryGroup[0] && ip_equal(bcast_ip,ip) && name[0] != '*') { - strcpy(PrimaryGroup,name); - strupper(PrimaryGroup); - DEBUG(3,("Setting primary group to %s (%s)\n",PrimaryGroup,inet_ntoa(ip))); - } - - add_domain(d); - - ip = *interpret_addr2("255.255.255.255"); - if (name[0] != '*') add_host_entry(name,0x1e,False,0,SELF,ip); - - DEBUG(3,("Added domain entry %s at %s\n", - name,inet_ntoa(ip))); - - return(d); -} - -/**************************************************************************** - add a server entry - ****************************************************************************/ -struct server_record *add_server_entry(char *name,int servertype, - int ttl,char *comment,BOOL replace) -{ - BOOL newentry=False; - struct server_record *s; - - for (s = serverlist; s; s = s->next) - if (strequal(name,s->name)) break; - - if (s && !replace) { - DEBUG(4,("Not replacing %s\n",name)); - return(s); - } - - updatedlists=True; - - if (!s) { - newentry = True; - s = (struct server_record *)malloc(sizeof(*s)); - - if (!s) return(NULL); - - bzero((char *)s,sizeof(*s)); - } - - /* update the entry */ - StrnCpy(s->name,name,sizeof(s->name)-1); - StrnCpy(s->comment,comment,sizeof(s->comment)-1); - s->servertype = servertype; - s->death_time = ttl?time(NULL)+ttl*3:0; - strupper(s->name); - if (s->servertype & SV_TYPE_DOMAIN_ENUM) strupper(s->comment); - - if (!newentry) return(s); - - add_server(s); - - if (newentry) { - DEBUG(3,("Added server entry %s of type %x (%s)\n", - name,servertype,comment)); - } else { - DEBUG(3,("Updated server entry %s of type %x (%s)\n", - name,servertype,comment)); - } - - return(s); -} - - -/**************************************************************************** - add the magic samba names, useful for finding samba servers - **************************************************************************/ -static void add_my_names(void) -{ - struct in_addr ip; - - ip = *interpret_addr2("0.0.0.0"); - - add_host_entry(myname,0x20,True,0,SELF,ip); - add_host_entry(myname,0x0,True,0,SELF,ip); - add_host_entry(myname,0x1f,True,0,SELF,ip); /* used for chat?? */ - add_host_entry(myname,0x3,True,0,SELF,ip); /* used for winpopup */ - - if (!domainlist) - add_domain_entry(lp_workgroup(),bcast_ip); - add_server_entry(myname, - ServerType, - 0,ServerComment,True); - - add_host_entry("__SAMBA__",0x20,True,0,SELF,ip); - add_host_entry("__SAMBA__",0x0,True,0,SELF,ip); - - if (lp_preferred_master()) { - DEBUG(3,("Preferred master startup\n")); - needelection = True; - ElectionCriterion |= (1<<3); - } - - ElectionCriterion |= (lp_os_level() << 24); -} - - -/******************************************************************* - write out browse.dat - ******************************************************************/ -static void write_browse_list(void) -{ - struct server_record *s; - pstring fname,fnamenew; - FILE *f; - - 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 (s=serverlist; s ; s = s->next) { - /* don't list domains I don't have a master for */ - if ((s->servertype & SV_TYPE_DOMAIN_ENUM) && !s->comment[0]) continue; - - fprintf(f,"\"%s\"\t%08x\t\"%s\"\n",s->name,s->servertype,s->comment); - } - - - fclose(f); - chmod(fnamenew,0644); - /* unlink(fname); */ - rename(fnamenew,fname); - DEBUG(3,("Wrote browse list %s\n",fname)); -} - -/******************************************************************* - expire old names in the namelist and serverlist - ******************************************************************/ -static void expire_names(void) -{ - static time_t lastrun=0; - time_t t = time(NULL); - struct name_record *n; - struct name_record *next; - struct server_record *s; - struct server_record *nexts; - - if (!lastrun) lastrun = t; - if (t < lastrun + 5) return; - lastrun = t; - - /* expire old names */ - for (n = namelist; n; n = next) { - if (n->death_time && n->death_time < t) { - DEBUG(3,("Removing dead name %s\n", - namestr(&n->name))); - next = n->next; - if (n->prev) n->prev->next = n->next; - if (n->next) n->next->prev = n->prev; - if (namelist == n) namelist = n->next; - free(n); - } else { - next = n->next; - } - } - - /* expire old entries in the serverlist */ - for (s = serverlist; s; s = nexts) { - if (s->death_time && s->death_time < t) { - DEBUG(3,("Removing dead server %s\n",s->name)); - updatedlists = True; - nexts = s->next; - if (s->prev) s->prev->next = s->next; - if (s->next) s->next->prev = s->prev; - if (serverlist == s) serverlist = s->next; - free(s); - } else { - nexts = s->next; - } - } -} - - -/******************************************************************* - delete old names from the namelist - ******************************************************************/ -static void housekeeping(void) -{ - time_t t = time(NULL); - - expire_names(); - - /* write out the browse.dat database for smbd to get */ - if (updatedlists) { - write_browse_list(); - updatedlists = False; - } - - { - /* occasionally check to see if the master browser is around */ - static time_t lastrun=0; - if (!lastrun) lastrun = t; - if (t < lastrun + 5*60) return; - lastrun = t; - - if (!AM_MASTER && PrimaryGroup[0] && - !name_query(ClientNMB,PrimaryGroup,0x1d,True,False, - bcast_ip,NULL,queue_packet)) { - DEBUG(2,("Forcing election on %s\n",PrimaryGroup)); - needelection = True; - } - } -} - - -/**************************************************************************** - reload the services file - **************************************************************************/ -BOOL reload_services(BOOL test) -{ - BOOL ret; - extern fstring remote_machine; - - strcpy(remote_machine,"nmbd"); - - if (lp_loaded()) - { - pstring fname; - strcpy(fname,lp_configfile()); - if (file_exist(fname,NULL) && !strcsequal(fname,servicesf)) - { - strcpy(servicesf,fname); - test = False; - } - } - - if (test && !lp_file_list_changed()) - return(True); - - ret = lp_load(servicesf,True); - - /* perhaps the config filename is now set */ - if (!test) - reload_services(True); - - return(ret); -} - - - -/**************************************************************************** -load a netbios hosts file -****************************************************************************/ -static void load_hosts_file(char *fname) -{ - FILE *f = fopen(fname,"r"); - pstring line; - if (!f) { - DEBUG(2,("Can't open lmhosts file %s\n",fname)); - return; - } - - while (!feof(f)) - { - if (!fgets_slash(line,sizeof(pstring),f)) continue; - - if (*line == '#') continue; - - { - BOOL group=False; - string ip,name,flags,extra; - char *ptr; - int count = 0; - struct in_addr ipaddr; - enum name_source source = LMHOSTS; - - *ip = *name = *flags = *extra = 0; - - ptr = line; - - if (next_token(&ptr,ip,NULL)) ++count; - if (next_token(&ptr,name,NULL)) ++count; - if (next_token(&ptr,flags,NULL)) ++count; - if (next_token(&ptr,extra,NULL)) ++count; - - if (count <= 0) continue; - - if (count > 0 && count < 2) - { - DEBUG(0,("Ill formed hosts line [%s]\n",line)); - continue; - } - - if (strchr(flags,'G') || strchr(flags,'S')) - group = True; - - if (strchr(flags,'M') && !group) { - source = SELF; - strcpy(myname,name); - } - - ipaddr = *interpret_addr2(ip); - - if (group) { - add_domain_entry(name,ipaddr); - } else { - add_host_entry(name,0x20,True,0,source,ipaddr); - } - } - } - - fclose(f); -} - -/******************************************************************* - check if 2 IPs are on the same net - we will assume the local netmask, although this could be wrong XXXX - ******************************************************************/ -static BOOL same_net(struct in_addr ip1,struct in_addr ip2) -{ - unsigned long net1,net2,nmask; - - nmask = ntohl(Netmask.s_addr); - net1 = ntohl(ip1.s_addr); - net2 = ntohl(ip2.s_addr); - - return((net1 & nmask) == (net2 & nmask)); -} - -/**************************************************************************** - send an election packet - **************************************************************************/ -static void send_election(char *group,uint32 criterion,int timeup,char *name) -{ - pstring outbuf; - char *p; - - DEBUG(2,("Sending election to %s for workgroup %s\n", - inet_ntoa(bcast_ip),group)); - - bzero(outbuf,sizeof(outbuf)); - p = outbuf; - CVAL(p,0) = 8; /* election */ - p++; - - CVAL(p,0) = ELECTION_VERSION; - SIVAL(p,1,criterion); - SIVAL(p,5,timeup*1000); /* ms - despite the spec */ - p += 13; - strcpy(p,name); - strupper(p); - p = skip_string(p,1); - - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - name,group,0,0x1e,bcast_ip,myip); -} - - -/**************************************************************************** - send a backup list response - **************************************************************************/ -static void send_backup_list(char *name,int token,struct nmb_name *to, - struct in_addr ip) -{ - pstring outbuf; - char *p; - - DEBUG(2,("Sending backup list to %s for workgroup %s\n", - inet_ntoa(ip),PrimaryGroup)); - - bzero(outbuf,sizeof(outbuf)); - p = outbuf; - CVAL(p,0) = 10; /* backup list response */ - p++; - - CVAL(p,0) = 1; /* count */ - SIVAL(p,1,token); - p += 5; - strcpy(p,name); - strupper(p); - p = skip_string(p,1) + 1; - - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - myname,to->name,0,to->name_type,ip,myip); -} - - -/******************************************************************* - become the master browser - ******************************************************************/ -static void become_master(void) -{ - uint32 domain_type = SV_TYPE_DOMAIN_ENUM | SV_TYPE_SERVER_UNIX; - DEBUG(2,("Becoming master for %s\n",PrimaryGroup)); - - ServerType |= SV_TYPE_MASTER_BROWSER; - ServerType |= SV_TYPE_BACKUP_BROWSER; - ElectionCriterion |= 0x5; - - add_host_entry(PrimaryGroup,0x1d,True,0,SELF,myip); - add_host_entry(PrimaryGroup,0x0,False,0,SELF,myip); - add_host_entry(MSBROWSE,1,False,0,SELF,myip); - - if (lp_domain_master()) { - add_host_entry(myname,0x1b,True,0,SELF,myip); - add_host_entry(PrimaryGroup,0x1b,True,0,SELF,myip); - add_host_entry(PrimaryGroup,0x1c,False,0,SELF,myip); - ServerType |= SV_TYPE_DOMAIN_MASTER; - if (lp_domain_logons()) { - ServerType |= SV_TYPE_DOMAIN_CTRL; - ServerType |= SV_TYPE_DOMAIN_MEMBER; - domain_type |= SV_TYPE_DOMAIN_CTRL; - } - } - - add_server_entry(PrimaryGroup,domain_type,0,myname,True); - add_server_entry(myname,ServerType,0,ServerComment,True); - - announce_request(PrimaryGroup); - - needannounce = True; -} - - -/******************************************************************* - unbecome the master browser - ******************************************************************/ -static void become_nonmaster(void) -{ - struct name_record *n; - struct nmb_name nn; - - DEBUG(2,("Becoming non-master for %s\n",PrimaryGroup)); - - ServerType &= ~SV_TYPE_MASTER_BROWSER; - ServerType &= ~SV_TYPE_DOMAIN_CTRL; - ServerType &= ~SV_TYPE_DOMAIN_MASTER; - - ElectionCriterion &= ~0x4; - - make_nmb_name(&nn,PrimaryGroup,0x1d,scope); - n = find_name(&nn); - if (n && n->source == SELF) remove_name(n); - - make_nmb_name(&nn,PrimaryGroup,0x1b,scope); - n = find_name(&nn); - if (n && n->source == SELF) remove_name(n); - - make_nmb_name(&nn,MSBROWSE,1,scope); - n = find_name(&nn); - if (n && n->source == SELF) remove_name(n); -} - - -/******************************************************************* - run the election - ******************************************************************/ -static void run_election(void) -{ - time_t t = time(NULL); - static time_t lastime = 0; - - if (!PrimaryGroup[0] || !RunningElection) return; - - /* send election packets once a second */ - if (lastime && - t-lastime <= 0) return; - - lastime = t; - - send_election(PrimaryGroup,ElectionCriterion,t-StartupTime,myname); - - if (ElectionCount++ < 4) return; - - /* I won! now what :-) */ - RunningElection = False; - DEBUG(2,(">>> Won election on %s <<<\n",PrimaryGroup)); - become_master(); -} - - -/**************************************************************************** - construct a host announcement unicast - **************************************************************************/ -static void announce_host(struct domain_record *d,char *my_name,char *comment) -{ - time_t t = time(NULL); - pstring outbuf; - char *p; - char *namep; - char *stypep; - char *commentp; - uint32 stype = ServerType; - - if (needannounce) { - /* drop back to a max 3 minute announce - this is to prevent a - single lost packet from stuffing things up for too long */ - d->announce_interval = MIN(d->announce_interval,3*60); - d->lastannounce_time = t - (d->announce_interval+1); - } - - /* announce every minute at first then progress to every 12 mins */ - if (d->lastannounce_time && - (t - d->lastannounce_time) < d->announce_interval) - return; - - if (d->announce_interval < 12*60) d->announce_interval += 60; - d->lastannounce_time = t; - - DEBUG(2,("Sending announcement to %s for workgroup %s\n", - inet_ntoa(d->bcast_ip),d->name)); - - if (!strequal(PrimaryGroup,d->name) || - !ip_equal(bcast_ip,d->bcast_ip)) { - stype &= ~(SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER | - SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER | - SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER); - } - - if (!*comment) comment = "NoComment"; - if (!*my_name) my_name = "NoName"; - - if (strlen(comment) > 43) comment[43] = 0; - - bzero(outbuf,sizeof(outbuf)); - CVAL(outbuf,0) = 1; /* host announce */ - p = outbuf+1; - - CVAL(p,0) = updatecount; - SIVAL(p,1,d->announce_interval*1000); /* ms - despite the spec */ - namep = p+5; - StrnCpy(p+5,my_name,16); - strupper(p+5); - CVAL(p,21) = 2; /* major version */ - CVAL(p,22) = 2; /* minor version */ - stypep = p+23; - SIVAL(p,23,stype); - SSVAL(p,27,0xaa55); /* browse signature */ - SSVAL(p,29,1); /* browse version */ - commentp = p+31; - strcpy(p+31,comment); - p += 31; - p = skip_string(p,1); - - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - my_name,d->name,0,0x1d,d->bcast_ip,myip); - - /* if I'm the master then I also need to do a local master and - domain announcement */ - - if (AM_MASTER && - strequal(d->name,PrimaryGroup) && - ip_equal(bcast_ip,d->bcast_ip)) { - - /* do master announcements as well */ - SIVAL(stypep,0,ServerType); - - CVAL(outbuf,0) = 15; /* local master announce */ - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - my_name,PrimaryGroup,0,0x1e,d->bcast_ip,myip); - - CVAL(outbuf,0) = 12; /* domain announce */ - StrnCpy(namep,PrimaryGroup,15); - strupper(namep); - StrnCpy(commentp,myname,15); - strupper(commentp); - SIVAL(stypep,0,(unsigned)0x80000000); - p = commentp + strlen(commentp) + 1; - - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - my_name,MSBROWSE,0,1,d->bcast_ip,myip); - } -} - - -/**************************************************************************** - send a announce request to the local net - **************************************************************************/ -static void announce_request(char *group) -{ - pstring outbuf; - char *p; - - DEBUG(2,("Sending announce request to %s for workgroup %s\n", - inet_ntoa(bcast_ip),group)); - - bzero(outbuf,sizeof(outbuf)); - p = outbuf; - CVAL(p,0) = 2; /* announce request */ - p++; - - CVAL(p,0) = 0; /* flags?? */ - p++; - StrnCpy(p,myname,16); - strupper(p); - p = skip_string(p,1); - - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - myname,group,0,0,bcast_ip,myip); -} - -/**************************************************************************** - announce myself as a master to the PDC - **************************************************************************/ -static void announce_master(char *group) -{ - static time_t last=0; - time_t t = time(NULL); - pstring outbuf; - char *p; - struct in_addr ip,pdc_ip; - fstring pdcname; - *pdcname = 0; - - if (strequal(domain_controller(),myname)) return; - - if (!AM_MASTER || (last && (t-last < 10*60))) return; - last = t; - - ip = *interpret_addr2(domain_controller()); - - if (zero_ip(ip)) ip = bcast_ip; - - if (!name_query(ClientNMB,PrimaryGroup, - 0x1b,False,False,ip,&pdc_ip,queue_packet)) { - DEBUG(2,("Failed to find PDC at %s\n",domain_controller())); - return; - } - - name_status(ClientNMB,PrimaryGroup,0x1b,False, - pdc_ip,NULL,pdcname,queue_packet); - - if (!pdcname[0]) { - DEBUG(3,("Can't find netbios name of PDC at %s\n",inet_ntoa(pdc_ip))); - } else { - sync_browse_lists(pdcname,0x20,myname,PrimaryGroup,pdc_ip); - } - - - DEBUG(2,("Sending master announce to %s for workgroup %s\n", - inet_ntoa(pdc_ip),group)); - - bzero(outbuf,sizeof(outbuf)); - p = outbuf; - CVAL(p,0) = 13; /* announce request */ - p++; - - StrnCpy(p,myname,16); - strupper(p); - p = skip_string(p,1); - - send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf), - myname,PrimaryGroup,0x1b,0,pdc_ip,myip); -} - - -/******************************************************************* - am I listening on a name. Should check name_type as well - - This is primarily used to prevent us gathering server lists from - other workgroups we aren't a part of - ******************************************************************/ -static BOOL listening(struct nmb_name *n) -{ - if (!strequal(n->scope,scope)) return(False); - - if (strequal(n->name,myname) || - strequal(n->name,PrimaryGroup) || - strequal(n->name,MSBROWSE)) - return(True); - - return(False); -} - - -/******************************************************************* - process a domain announcement frame - - Announce frames come in 3 types. Servers send host announcements - (command=1) to let the master browswer know they are - available. Master browsers send local master announcements - (command=15) to let other masters and backups that they are the - master. They also send domain announcements (command=12) to register - the domain - - The comment field of domain announcements contains the master - browser name. The servertype is used by NetServerEnum to select - resources. We just have to pass it to smbd (via browser.dat) and let - the client choose using bit masks. - ******************************************************************/ -static void process_announce(struct packet_struct *p,int command,char *buf) -{ - struct dgram_packet *dgram = &p->packet.dgram; - int update_count = CVAL(buf,0); - int ttl = IVAL(buf,1)/1000; - char *name = buf+5; - int osmajor=CVAL(buf,21); - int osminor=CVAL(buf,22); - uint32 servertype = IVAL(buf,23); - char *comment = buf+31; - - name[15] = 0; - comment[43] = 0; - - DEBUG(3,("Announce(%d) %s count=%d ttl=%d OS=(%d,%d) type=%08x comment=%s\n", - command,name,update_count,ttl,osmajor,osminor, - servertype,comment)); - - if (strequal(dgram->source_name.name,myname)) return; - - if (!listening(&dgram->dest_name)) return; - - ttl = GET_TTL(ttl); - - /* add them to our browse list */ - add_server_entry(name,servertype,ttl,comment,True); - -} - -/******************************************************************* - process a master announcement frame - ******************************************************************/ -static void process_master_announce(struct packet_struct *p,char *buf) -{ - struct dgram_packet *dgram = &p->packet.dgram; - char *name = buf; - - name[15] = 0; - - DEBUG(3,("Master Announce from %s (%s)\n",name,inet_ntoa(p->ip))); - - if (strequal(dgram->source_name.name,myname)) return; - - if (!AM_MASTER || !listening(&dgram->dest_name)) return; - - /* merge browse lists with them */ - if (lp_domain_master()) - sync_browse_lists(name,0x20,myname,PrimaryGroup,p->ip); -} - - -/******************************************************************* - process a backup list request - - A client send a backup list request to ask for a list of servers on - the net that maintain server lists for a domain. A server is then - chosen from this list to send NetServerEnum commands to to list - available servers. - - Currently samba only sends back one name in the backup list, its - wn. For larger nets we'll have to add backups and send "become - backup" requests occasionally. - ******************************************************************/ -static void process_backup_list(struct packet_struct *p,char *buf) -{ - struct dgram_packet *dgram = &p->packet.dgram; - int count = CVAL(buf,0); - int token = IVAL(buf,1); - - DEBUG(3,("Backup request to %s token=%d\n", - namestr(&dgram->dest_name), - token)); - - if (strequal(dgram->source_name.name,myname)) return; - - if (count <= 0) return; - - if (!AM_MASTER || - !strequal(PrimaryGroup,dgram->dest_name.name)) - return; - - if (!listening(&dgram->dest_name)) return; - - send_backup_list(myname,token, - &dgram->source_name, - p->ip); -} - - -/******************************************************************* - work out if I win an election - ******************************************************************/ -static BOOL win_election(int version,uint32 criterion,int timeup,char *name) -{ - time_t t = time(NULL); - uint32 mycriterion; - if (version > ELECTION_VERSION) return(False); - if (version < ELECTION_VERSION) return(True); - - mycriterion = ElectionCriterion; - - if (criterion > mycriterion) return(False); - if (criterion < mycriterion) return(True); - - if (timeup > (t - StartupTime)) return(False); - if (timeup < (t - StartupTime)) return(True); - - if (strcasecmp(myname,name) > 0) return(False); - - return(True); -} - - -/******************************************************************* - process a election packet - - An election dynamically decides who will be the master. - ******************************************************************/ -static void process_election(struct packet_struct *p,char *buf) -{ - struct dgram_packet *dgram = &p->packet.dgram; - int version = CVAL(buf,0); - uint32 criterion = IVAL(buf,1); - int timeup = IVAL(buf,5)/1000; - char *name = buf+13; - - name[15] = 0; - - DEBUG(3,("Election request from %s vers=%d criterion=%08x timeup=%d\n", - name,version,criterion,timeup)); - - if (strequal(dgram->source_name.name,myname)) return; - - if (!listening(&dgram->dest_name)) return; - - if (win_election(version,criterion,timeup,name)) { - if (!RunningElection) { - needelection = True; - ElectionCount=0; - } - } else { - needelection = False; - if (RunningElection) { - RunningElection = False; - DEBUG(3,(">>> Lost election on %s <<<\n",PrimaryGroup)); - - /* if we are the master then remove our masterly names */ - if (AM_MASTER) - become_nonmaster(); - } - } -} - - -/******************************************************************* - process a announcement request - - clients send these when they want everyone to send an announcement - immediately. This can cause quite a storm of packets! - ******************************************************************/ -static void process_announce_request(struct packet_struct *p,char *buf) -{ - struct dgram_packet *dgram = &p->packet.dgram; - int flags = CVAL(buf,0); - char *name = buf+1; - - name[15] = 0; - - DEBUG(3,("Announce request from %s flags=0x%X\n",name,flags)); - - if (strequal(dgram->source_name.name,myname)) return; - - needannounce = True; -} - - -/**************************************************************************** -process a browse frame -****************************************************************************/ -static void process_browse_packet(struct packet_struct *p,char *buf,int len) -{ - int command = CVAL(buf,0); - switch (command) - { - case 1: /* host announce */ - case 12: /* domain announce */ - case 15: /* local master announce */ - process_announce(p,command,buf+1); - break; - - case 2: /* announce request */ - process_announce_request(p,buf+1); - break; - - case 8: /* election */ - process_election(p,buf+1); - break; - - case 9: /* get backup list */ - process_backup_list(p,buf+1); - break; - - case 13: /* master announcement */ - process_master_announce(p,buf+1); - break; - } -} - - -/**************************************************************************** - process a domain logon packet - **************************************************************************/ -static void process_logon_packet(struct packet_struct *p,char *buf,int len) -{ - char *logname,*q; - pstring outbuf; - struct dgram_packet *dgram = &p->packet.dgram; - int code; - - if (!lp_domain_logons()) { - DEBUG(3,("No domain logons\n")); - return; - } - if (!listening(&dgram->dest_name)) { - DEBUG(4,("Not listening to that domain\n")); - return; - } - - q = outbuf; - bzero(outbuf,sizeof(outbuf)); - - code = SVAL(buf,0); - switch (code) { - case 0: - { - char *machine = buf+2; - char *user = skip_string(machine,1); - logname = skip_string(user,1); - - SSVAL(q,0,6); - q += 2; - strcpy(q,"\\\\"); - q += 2; - StrnCpy(q,myname,16); - strupper(q); - q = skip_string(q,1); - SSVAL(q,0,0xFFFF); - q += 2; - - DEBUG(3,("Domain login request from %s(%s) user=%s\n", - machine,inet_ntoa(p->ip),user)); - } - break; - case 7: - { - char *machine = buf+2; - logname = skip_string(machine,1); - - SSVAL(q,0,0xc); - q += 2; - StrnCpy(q,domain_controller(),16); - strupper(q); - q = skip_string(q,1); - q += PutUniCode(q,domain_controller()); - q += PutUniCode(q,dgram->dest_name.name); - SSVAL(q,0,0xFFFF); - q += 2; - - DEBUG(3,("GETDC request from %s(%s)\n", - machine,inet_ntoa(p->ip))); - } - break; - default: - DEBUG(3,("Unknown domain request %d\n",code)); - return; - } - - - send_mailslot_reply(logname,ClientDGRAM,outbuf,PTR_DIFF(q,outbuf), - myname,&dgram->source_name.name[0],0,0,p->ip,myip); -} - -/**************************************************************************** -process udp 138 datagrams -****************************************************************************/ -static void process_dgram(struct packet_struct *p) -{ - char *buf; - char *buf2; - int len; - struct dgram_packet *dgram = &p->packet.dgram; - - if (dgram->header.msg_type != 0x10 && - dgram->header.msg_type != 0x11 && - dgram->header.msg_type != 0x12) { - /* don't process error packets etc yet */ - return; - } - - buf = &dgram->data[0]; - buf -= 4; /* XXXX for the pseudo tcp length - - someday I need to get rid of this */ - - if (CVAL(buf,smb_com) != SMBtrans) return; - - len = SVAL(buf,smb_vwv11); - buf2 = smb_base(buf) + SVAL(buf,smb_vwv12); - - DEBUG(3,("datagram from %s to %s for %s of type %d len=%d\n", - namestr(&dgram->source_name),namestr(&dgram->dest_name), - smb_buf(buf),CVAL(buf2,0),len)); - - if (len <= 0) return; - - if (strequal(smb_buf(buf),"\\MAILSLOT\\BROWSE")) { - process_browse_packet(p,buf2,len); - } else if (strequal(smb_buf(buf),"\\MAILSLOT\\NET\\NETLOGON")) { - process_logon_packet(p,buf2,len); - } - -} - -/******************************************************************* - find a workgroup using the specified broadcast - ******************************************************************/ -static BOOL find_workgroup(char *name,struct in_addr ip) -{ - fstring name1; - BOOL ret; - struct in_addr ipout; - - strcpy(name1,MSBROWSE); - - ret = name_query(ClientNMB,name1,0x1,True,False,ip,&ipout,queue_packet); - if (!ret) return(False); - - name_status(ClientNMB,name1,0x1,False,ipout,name,NULL,queue_packet); - - if (name[0] != '*') { - DEBUG(2,("Found workgroup %s on broadcast %s\n",name,inet_ntoa(ip))); - } else { - DEBUG(3,("Failed to find workgroup %s on broadcast %s\n",name,inet_ntoa(ip))); - } - return(name[0] != '*'); -} - - -/**************************************************************************** - a hook for announce handling - called every minute - **************************************************************************/ -static void do_announcements(void) -{ - struct domain_record *d; - - for (d = domainlist; d; d = d->next) { - /* if the ip address is 0 then set to the broadcast */ - if (zero_ip(d->bcast_ip)) d->bcast_ip = bcast_ip; - - /* if the workgroup is '*' then find a workgroup to be part of */ - if (d->name[0] == '*') { - if (!find_workgroup(d->name,d->bcast_ip)) continue; - add_host_entry(d->name,0x1e,False,0,SELF, - *interpret_addr2("255.255.255.255")); - if (!PrimaryGroup[0] && ip_equal(bcast_ip,d->bcast_ip)) { - strcpy(PrimaryGroup,d->name); - strupper(PrimaryGroup); - } - } - - announce_host(d,myname,ServerComment); - } - - /* if I have a domain controller then announce to it */ - if (AM_MASTER) - announce_master(PrimaryGroup); - - needannounce=False; -} - -/******************************************************************* - check if someone still owns a name - ******************************************************************/ -static BOOL confirm_name(struct name_record *n) -{ - struct in_addr ipout; - BOOL ret = name_query(ClientNMB,n->name.name, - n->name.name_type,False, - False,n->ip,&ipout,queue_packet); - return(ret && ip_equal(ipout,n->ip)); -} - -/**************************************************************************** -reply to a name release -****************************************************************************/ -static void reply_name_release(struct packet_struct *p) -{ - struct nmb_packet *nmb = &p->packet.nmb; - struct packet_struct p2; - struct nmb_packet *nmb2; - struct res_rec answer_rec; - struct in_addr ip; - int rcode=0; - int nb_flags = nmb->additional->rdata[0]; - BOOL bcast = nmb->header.nm_flags.bcast; - - - putip((char *)&ip,&nmb->additional->rdata[2]); - - { - struct name_record *n = find_name(&nmb->question.question_name); - if (n && n->unique && n->source == REGISTER && - ip_equal(ip,n->ip)) { - remove_name(n); n = NULL; - } - - /* XXXX under what conditions should we reject the removal?? */ - } - - DEBUG(3,("Name release on name %s rcode=%d\n", - namestr(&nmb->question.question_name),rcode)); - - if (bcast) return; - - /* Send a NAME RELEASE RESPONSE */ - p2 = *p; - nmb2 = &p2.packet.nmb; - - nmb2->header.response = True; - nmb2->header.nm_flags.bcast = False; - nmb2->header.nm_flags.recursion_available = CanRecurse; - nmb2->header.nm_flags.trunc = False; - nmb2->header.nm_flags.authoritative = True; - nmb2->header.qdcount = 0; - nmb2->header.ancount = 1; - nmb2->header.nscount = 0; - nmb2->header.arcount = 0; - nmb2->header.rcode = rcode; - - nmb2->answers = &answer_rec; - bzero((char *)nmb2->answers,sizeof(*nmb2->answers)); - - nmb2->answers->rr_name = nmb->question.question_name; - nmb2->answers->rr_type = nmb->question.question_type; - nmb2->answers->rr_class = nmb->question.question_class; - nmb2->answers->ttl = 0; - nmb2->answers->rdlength = 6; - nmb2->answers->rdata[0] = nb_flags; - putip(&nmb2->answers->rdata[2],(char *)&ip); - - send_packet(&p2); -} - -/**************************************************************************** - reply to a reg request - **************************************************************************/ -static void reply_name_reg(struct packet_struct *p) -{ - struct nmb_packet *nmb = &p->packet.nmb; - char *qname = nmb->question.question_name.name; - BOOL wildcard = (qname[0] == '*'); - BOOL bcast = nmb->header.nm_flags.bcast; - int ttl = GET_TTL(nmb->additional->ttl); - int name_type = nmb->question.question_name.name_type; - int nb_flags = nmb->additional->rdata[0]; - struct packet_struct p2; - struct nmb_packet *nmb2; - struct res_rec answer_rec; - struct in_addr ip; - BOOL group = (nb_flags&0x80)?True:False; - int rcode = 0; - - if (wildcard) return; - - putip((char *)&ip,&nmb->additional->rdata[2]); - - if (group) { - /* apparently we should return 255.255.255.255 for group queries (email from MS) */ - ip = *interpret_addr2("255.255.255.255"); - } - - { - struct name_record *n = find_name(&nmb->question.question_name); - - if (n) { - if (!group && !ip_equal(ip,n->ip)) { - /* check if the previous owner still wants it, - if so reject the registration, otherwise change the owner - and refresh */ - if (n->source != REGISTER || confirm_name(n)) { - rcode = 6; - } else { - n->ip = ip; - n->death_time = ttl?p->timestamp+ttl*3:0; - DEBUG(3,("%s changed owner to %s\n", - namestr(&n->name),inet_ntoa(n->ip))); - } - } else { - /* refresh the name */ - if (n->source != SELF) - n->death_time = ttl?p->timestamp + ttl*3:0; - } - } else { - /* add the name to our database */ - n = add_host_entry(qname,name_type,!group,ttl,REGISTER,ip); - } - } - - if (bcast) return; - - DEBUG(3,("Name registration for name %s at %s rcode=%d\n", - namestr(&nmb->question.question_name), - inet_ntoa(ip),rcode)); - - /* Send a NAME REGISTRATION RESPONSE */ - /* a lot of fields get copied from the query. This gives us the IP - and port the reply will be sent to etc */ - p2 = *p; - nmb2 = &p2.packet.nmb; - - nmb2->header.opcode = 5; - nmb2->header.response = True; - nmb2->header.nm_flags.bcast = False; - nmb2->header.nm_flags.recursion_available = CanRecurse; - nmb2->header.nm_flags.trunc = False; - nmb2->header.nm_flags.authoritative = True; - nmb2->header.qdcount = 0; - nmb2->header.ancount = 1; - nmb2->header.nscount = 0; - nmb2->header.arcount = 0; - nmb2->header.rcode = rcode; - - nmb2->answers = &answer_rec; - bzero((char *)nmb2->answers,sizeof(*nmb2->answers)); - - nmb2->answers->rr_name = nmb->question.question_name; - nmb2->answers->rr_type = nmb->question.question_type; - nmb2->answers->rr_class = nmb->question.question_class; - - nmb2->answers->ttl = ttl; - nmb2->answers->rdlength = 6; - nmb2->answers->rdata[0] = nb_flags; - putip(&nmb2->answers->rdata[2],(char *)&ip); - - send_packet(&p2); -} - - -/**************************************************************************** -reply to a name status query -****************************************************************************/ -static void reply_name_status(struct packet_struct *p) -{ - struct nmb_packet *nmb = &p->packet.nmb; - char *qname = nmb->question.question_name.name; - BOOL wildcard = (qname[0] == '*'); - struct packet_struct p2; - struct nmb_packet *nmb2; - struct res_rec answer_rec; - char *buf; - int count; - int rcode = 0; - struct name_record *n = find_name(&nmb->question.question_name); - - DEBUG(3,("Name status for name %s\n", - namestr(&nmb->question.question_name))); - - if (!wildcard && (!n || n->source != SELF)) - return; - - /* Send a POSITIVE NAME STATUS RESPONSE */ - /* a lot of fields get copied from the query. This gives us the IP - and port the reply will be sent to etc */ - p2 = *p; - nmb2 = &p2.packet.nmb; - - nmb2->header.response = True; - nmb2->header.nm_flags.bcast = False; - nmb2->header.nm_flags.recursion_available = CanRecurse; - nmb2->header.nm_flags.trunc = False; - nmb2->header.nm_flags.authoritative = True; /* WfWg ignores - non-authoritative answers */ - nmb2->header.qdcount = 0; - nmb2->header.ancount = 1; - nmb2->header.nscount = 0; - nmb2->header.arcount = 0; - nmb2->header.rcode = rcode; - - nmb2->answers = &answer_rec; - bzero((char *)nmb2->answers,sizeof(*nmb2->answers)); - - - nmb2->answers->rr_name = nmb->question.question_name; - nmb2->answers->rr_type = nmb->question.question_type; - nmb2->answers->rr_class = nmb->question.question_class; - nmb2->answers->ttl = 0; - - for (count=0, n = namelist ; n; n = n->next) { - if (n->source != SELF) continue; - count++; - } - - count = MIN(count,400/18); /* XXXX hack, we should calculate exactly - how many will fit */ - - - buf = &nmb2->answers->rdata[0]; - SCVAL(buf,0,count); - buf += 1; - - for (n = namelist ; n; n = n->next) - { - if (n->source != SELF) continue; - - bzero(buf,18); - strcpy(buf,n->name.name); - strupper(buf); - buf[15] = n->name.name_type; - buf += 16; - buf[0] = 0x4; /* active */ - if (!n->unique) buf[0] |= 0x80; /* group */ - buf += 2; - count--; - } - - /* XXXXXXX we should fill in more fields of the statistics structure */ - bzero(buf,64); - { - extern int num_good_sends,num_good_receives; - SIVAL(buf,20,num_good_sends); - SIVAL(buf,24,num_good_receives); - } - SIVAL(buf,46,0xFFB8E5); /* undocumented - used by NT */ - - buf += 64; - - nmb2->answers->rdlength = PTR_DIFF(buf,&nmb2->answers->rdata[0]); - - send_packet(&p2); -} - - - -/**************************************************************************** -reply to a name query -****************************************************************************/ -static void reply_name_query(struct packet_struct *p) -{ - struct nmb_packet *nmb = &p->packet.nmb; - char *qname = nmb->question.question_name.name; - BOOL wildcard = (qname[0] == '*'); - BOOL bcast = nmb->header.nm_flags.bcast; - struct in_addr retip; - int name_type = nmb->question.question_name.name_type; - struct packet_struct p2; - struct nmb_packet *nmb2; - struct res_rec answer_rec; - int ttl=0; - int rcode=0; - BOOL unique = True; - - DEBUG(3,("Name query for %s from %s (bcast=%s) - ", - namestr(&nmb->question.question_name), - inet_ntoa(p->ip), - BOOLSTR(bcast))); - - if (wildcard) - retip = myip; - - if (!wildcard) { - struct name_record *n = find_name(&nmb->question.question_name); - - if (!n) { - struct in_addr ip; - unsigned long a; - - /* only do DNS lookups if the query is for type 0x20 or type 0x0 */ - if (name_type != 0x20 && name_type != 0) { - DEBUG(3,("not found\n")); - return; - } - - /* look it up with DNS */ - a = interpret_addr(qname); - - putip((char *)&ip,(char *)&a); - - if (!a) { - /* no luck with DNS. We could possibly recurse here XXXX */ - /* if this isn't a bcast then we should send a negative reply XXXX */ - DEBUG(3,("no recursion\n")); - add_host_entry(qname,name_type,True,60*60,DNSFAIL,ip); - return; - } - - /* add it to our cache of names. give it 2 hours in the cache */ - n = add_host_entry(qname,name_type,True,2*60*60,DNS,ip); - - /* failed to add it? yikes! */ - if (!n) return; - } - - /* don't respond to bcast queries for group names unless we own them */ - if (bcast && !n->unique && !n->source == SELF) { - DEBUG(3,("no bcast replies\n")); - return; - } - - /* don't respond to bcast queries for addresses on the same net as the - machine doing the querying unless its our IP */ - if (bcast && - n->source != SELF && - same_net(n->ip,p->ip)) { - DEBUG(3,("same net\n")); - return; - } - - /* is our entry already dead? */ - if (n->death_time) { - if (n->death_time < p->timestamp) return; - ttl = n->death_time - p->timestamp; - } - - retip = n->ip; - unique = n->unique; - - /* it may have been an earlier failure */ - if (n->source == DNSFAIL) { - DEBUG(3,("DNSFAIL\n")); - return; - } - } - - /* if the IP is 0 then substitute my IP - we should see which one is on the - right interface for the caller to do this right XXX */ - if (zero_ip(retip)) retip = myip; - - DEBUG(3,("OK %s rcode=%d\n",inet_ntoa(retip),rcode)); - - /* a lot of fields get copied from the query. This gives us the IP - and port the reply will be sent to etc */ - p2 = *p; - nmb2 = &p2.packet.nmb; - - nmb2->header.response = True; - nmb2->header.nm_flags.bcast = False; - nmb2->header.nm_flags.recursion_available = CanRecurse; - nmb2->header.nm_flags.trunc = False; - nmb2->header.nm_flags.authoritative = True; /* WfWg ignores - non-authoritative answers */ - nmb2->header.qdcount = 0; - nmb2->header.ancount = 1; - nmb2->header.nscount = 0; - nmb2->header.arcount = 0; - nmb2->header.rcode = rcode; - - nmb2->answers = &answer_rec; - bzero((char *)nmb2->answers,sizeof(*nmb2->answers)); - - nmb2->answers->rr_name = nmb->question.question_name; - nmb2->answers->rr_type = nmb->question.question_type; - nmb2->answers->rr_class = nmb->question.question_class; - nmb2->answers->ttl = ttl; - nmb2->answers->rdlength = 6; - nmb2->answers->rdata[0] = unique?0:0x80; - nmb2->answers->rdata[1] = 0; - putip(&nmb2->answers->rdata[2],(char *)&retip); - - send_packet(&p2); -} - - - -/* the global packet linked-list. incoming entries are added to the - end of this list. it is supposed to remain fairly short so we - won't bother with an end pointer. */ -static struct packet_struct *packet_queue = NULL; - - -/******************************************************************* - queue a packet into the packet queue - ******************************************************************/ -static void queue_packet(struct packet_struct *packet) -{ - struct packet_struct *p; - if (!packet_queue) { - packet->prev = NULL; - packet->next = NULL; - packet_queue = packet; - return; - } - - /* find the bottom */ - for (p=packet_queue;p->next;p=p->next) ; - - p->next = packet; - packet->next = NULL; - packet->prev = p; -} - -/**************************************************************************** - process a nmb packet - ****************************************************************************/ -static void process_nmb(struct packet_struct *p) -{ - struct nmb_packet *nmb = &p->packet.nmb; - - /* if this is a response then ignore it */ - if (nmb->header.response) return; - - switch (nmb->header.opcode) - { - case 5: - case 8: - case 9: - if (nmb->header.qdcount>0 && - nmb->header.arcount>0) { - reply_name_reg(p); - return; - } - break; - - case 0: - if (nmb->header.qdcount>0) - { - switch (nmb->question.question_type) - { - case 0x20: - reply_name_query(p); - break; - - case 0x21: - reply_name_status(p); - break; - } - return; - } - break; - - case 6: - if (nmb->header.qdcount>0 && - nmb->header.arcount>0) { - reply_name_release(p); - return; - } - break; - } - -} - - - -/******************************************************************* - run elements off the packet queue till its empty - ******************************************************************/ -static void run_packet_queue(void) -{ - struct packet_struct *p; - - while ((p=packet_queue)) { - switch (p->packet_type) - { - case NMB_PACKET: - process_nmb(p); - break; - - case DGRAM_PACKET: - process_dgram(p); - break; - } - - packet_queue = packet_queue->next; - if (packet_queue) packet_queue->prev = NULL; - free_packet(p); - } -} - - -/**************************************************************************** - The main select loop, listen for packets and respond - ***************************************************************************/ -void process(void) -{ - - while (True) - { - fd_set fds; - int selrtn; - struct timeval timeout; - - if (needelection && PrimaryGroup[0] && !RunningElection) { - DEBUG(3,(">>> Starting election on %s <<<\n",PrimaryGroup)); - ElectionCount = 0; - RunningElection = True; - needelection = False; - } - - FD_ZERO(&fds); - FD_SET(ClientNMB,&fds); - FD_SET(ClientDGRAM,&fds); - /* during elections we need to send election packets at one - second intervals */ - timeout.tv_sec = RunningElection?1:NMBD_SELECT_LOOP; - timeout.tv_usec = 0; - - selrtn = sys_select(&fds,&timeout); - - if (FD_ISSET(ClientNMB,&fds)) { - struct packet_struct *packet = read_packet(ClientNMB,NMB_PACKET); - if (packet) queue_packet(packet); - } - - if (FD_ISSET(ClientDGRAM,&fds)) { - struct packet_struct *packet = read_packet(ClientDGRAM,DGRAM_PACKET); - if (packet) queue_packet(packet); - } - - if (RunningElection) - run_election(); - - run_packet_queue(); - - do_announcements(); - - housekeeping(); - } -} - - -/**************************************************************************** - open the socket communication -****************************************************************************/ -static BOOL open_sockets(BOOL isdaemon,int port) -{ - struct hostent *hp; - - /* get host info */ - if ((hp = Get_Hostbyname(myhostname)) == 0) - { - DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname)); - return False; - } - - if (isdaemon) - ClientNMB = open_socket_in(SOCK_DGRAM, port,0); - else - ClientNMB = 0; - - ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3); - - if (ClientNMB == -1) - return(False); - - signal(SIGPIPE, SIGNAL_CAST sig_pipe); - - set_socket_options(ClientNMB,"SO_BROADCAST"); - set_socket_options(ClientDGRAM,"SO_BROADCAST"); - - DEBUG(3, ("Socket opened.\n")); - return True; -} - - -/******************************************************************* - check that a IP, bcast and netmask and consistent. Must be a 1s - broadcast - ******************************************************************/ -static BOOL ip_consistent(struct in_addr ip,struct in_addr bcast, - struct in_addr nmask) -{ - unsigned long a_ip,a_bcast,a_nmask; - - a_ip = ntohl(ip.s_addr); - a_bcast = ntohl(bcast.s_addr); - a_nmask = ntohl(nmask.s_addr); - - /* check the netmask is sane */ - if (((a_nmask>>24)&0xFF) != 0xFF) { - DEBUG(0,("Insane netmask %s\n",inet_ntoa(nmask))); - return(False); - } - - /* check the IP and bcast are on the same net */ - if ((a_ip&a_nmask) != (a_bcast&a_nmask)) { - DEBUG(0,("IP and broadcast are on different nets!\n")); - return(False); - } - - /* check the IP and bcast are on the same net */ - if ((a_bcast|a_nmask) != 0xFFFFFFFF) { - DEBUG(0,("Not a ones based broadcast %s\n",inet_ntoa(bcast))); - return(False); - } - - return(True); -} - -/**************************************************************************** - initialise connect, service and file structs -****************************************************************************/ -static BOOL init_structs(void ) -{ - if (!get_myname(myhostname,got_myip?NULL:&myip)) - return(False); - - /* Read the broadcast address from the interface */ - { - struct in_addr ip0,ip1,ip2; - - ip0 = myip; - - if (!(got_bcast && got_nmask)) - { - get_broadcast(&ip0,&ip1,&ip2); - - if (!got_myip) - myip = ip0; - - if (!got_bcast) - bcast_ip = ip1; - - if (!got_nmask) - Netmask = ip2; - } - - DEBUG(1,("Using IP %s ",inet_ntoa(myip))); - DEBUG(1,("broadcast %s ",inet_ntoa(bcast_ip))); - DEBUG(1,("netmask %s\n",inet_ntoa(Netmask))); - - if (!ip_consistent(myip,bcast_ip,Netmask)) { - DEBUG(0,("WARNING: The IP address, broadcast and Netmask are not consistent\n")); - DEBUG(0,("You are likely to experience problems with this setup!\n")); - } - } - - if (! *myname) { - char *p; - strcpy(myname,myhostname); - p = strchr(myname,'.'); - if (p) *p = 0; - } - - { - extern fstring local_machine; - strcpy(local_machine,myname); - strupper(local_machine); - } - - return True; -} - -/**************************************************************************** -usage on the program -****************************************************************************/ -static void usage(char *pname) -{ - DEBUG(0,("Incorrect program usage - is the command line correct?\n")); - - printf("Usage: %s [-n name] [-B bcast address] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname); - printf("Version %s\n",VERSION); - printf("\t-D become a daemon\n"); - printf("\t-p port listen on the specified port\n"); - printf("\t-d debuglevel set the debuglevel\n"); - printf("\t-l log basename. Basename for log/debug files\n"); - printf("\t-n netbiosname. the netbios name to advertise for this host\n"); - printf("\t-B broadcast address the address to use for broadcasts\n"); - printf("\t-N netmask the netmask to use for subnet determination\n"); - printf("\t-H hosts file load a netbios hosts file\n"); - printf("\t-I ip-address override the IP address\n"); - printf("\t-G group name add a group name to be part of\n"); - printf("\t-C comment sets the machine comment that appears in browse lists\n"); - printf("\n"); -} - - -/**************************************************************************** - main program - **************************************************************************/ -int main(int argc,char *argv[]) -{ - int port = NMB_PORT; - int opt; - extern FILE *dbf; - extern char *optarg; - - *host_file = 0; - -#if 0 - sleep(10); -#endif - - StartupTime = time(NULL); - - TimeInit(); - - strcpy(debugf,NMBLOGFILE); - - setup_logging(argv[0],False); - - charset_initialise(); - -#ifdef LMHOSTSFILE - strcpy(host_file,LMHOSTSFILE); -#endif - - /* this is for people who can't start the program correctly */ - while (argc > 1 && (*argv[1] != '-')) - { - argv++; - argc--; - } - - fault_setup(fault_continue); - - signal(SIGHUP,SIGNAL_CAST sig_hup); - - bcast_ip = *interpret_addr2("0.0.0.0"); - myip = *interpret_addr2("0.0.0.0"); - - while ((opt = getopt (argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:")) != EOF) - switch (opt) - { - case 's': - strcpy(servicesf,optarg); - break; - case 'C': - strcpy(ServerComment,optarg); - break; - case 'G': - add_domain_entry(optarg,bcast_ip); - break; - case 'H': - strcpy(host_file,optarg); - break; - case 'I': - myip = *interpret_addr2(optarg); - got_myip = True; - break; - case 'B': - bcast_ip = *interpret_addr2(optarg); - got_bcast = True; - break; - case 'N': - Netmask = *interpret_addr2(optarg); - got_nmask = True; - break; - case 'n': - strcpy(myname,optarg); - break; - case 'l': - sprintf(debugf,"%s.nmb",optarg); - break; - case 'i': - strcpy(scope,optarg); - strupper(scope); - break; - case 'D': - is_daemon = True; - break; - case 'd': - DEBUGLEVEL = atoi(optarg); - break; - case 'p': - port = atoi(optarg); - break; - case 'h': - usage(argv[0]); - exit(0); - break; - default: - if (!is_a_socket(0)) - usage(argv[0]); - break; - } - - DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION)); - DEBUG(1,("Copyright Andrew Tridgell 1994\n")); - - init_structs(); - - if (!reload_services(False)) - return(-1); - - if (*host_file) - { - load_hosts_file(host_file); - DEBUG(3,("Loaded hosts file\n")); - } - - if (!*ServerComment) - strcpy(ServerComment,"Samba %v"); - string_sub(ServerComment,"%v",VERSION); - string_sub(ServerComment,"%h",myhostname); - - add_my_names(); - - DEBUG(3,("Checked names\n")); - - dump_names(); - - DEBUG(3,("Dumped names\n")); - - if (!is_daemon && !is_a_socket(0)) { - DEBUG(0,("standard input is not a socket, assuming -D option\n")); - is_daemon = True; - } - - - if (is_daemon) { - DEBUG(2,("%s becoming a daemon\n",timestring())); - become_daemon(); - } - - - DEBUG(3,("Opening sockets\n")); - - if (open_sockets(is_daemon,port)) - { - process(); - close_sockets(); - } - - if (dbf) - fclose(dbf); - return(0); -} |