From 64f0348a3f994334abe64a4d4896109c3c8c9039 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Sat, 13 Dec 1997 14:16:07 +0000 Subject: This is it ! The mega-merge of the JRA_NMBD_REWRITE branch back into the main tree. For the cvs logs of all the files starting nmbd_*.c, look in the JRA_NMBD_REWRITE branch. That branch has now been discontinued. Jeremy. (This used to be commit d80b0cb645f81d16734929a0b27a91c6650499bb) --- source3/nmbd/nmbd_sendannounce.c | 477 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 477 insertions(+) create mode 100644 source3/nmbd/nmbd_sendannounce.c (limited to 'source3/nmbd/nmbd_sendannounce.c') diff --git a/source3/nmbd/nmbd_sendannounce.c b/source3/nmbd/nmbd_sendannounce.c new file mode 100644 index 0000000000..e4b288aea5 --- /dev/null +++ b/source3/nmbd/nmbd_sendannounce.c @@ -0,0 +1,477 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + NBT netbios routines and daemon - version 2 + Copyright (C) Andrew Tridgell 1994-1997 + Copyright (C) Luke Kenneth Casson Leighton 1994-1997 + Copyright (C) Jeremy Allison 1994-1997 + + SMB Version handling + Copyright (C) John H Terpstra 1995-1997 + + 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" + +extern int DEBUGLEVEL; +extern pstring myname; +extern fstring myworkgroup; +extern char **my_netbios_names; +extern int updatecount; + +/**************************************************************************** + Send a browser reset packet. +**************************************************************************/ + +void send_browser_reset(int reset_type, char *to_name, int to_type, struct in_addr to_ip) +{ + pstring outbuf; + char *p; + + DEBUG(3,("send_browser_reset: sending reset request type %d to %s<%02x> IP %s.\n", + reset_type, to_name, to_type, inet_ntoa(to_ip) )); + + bzero(outbuf,sizeof(outbuf)); + p = outbuf; + CVAL(p,0) = ANN_ResetBrowserState; + p++; + CVAL(p,0) = reset_type; + p++; + + send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf), + myname, 0x0, to_name, to_type, to_ip, FIRST_SUBNET->myip); +} + +/**************************************************************************** + Broadcast a packet to the local net requesting that all servers in this + workgroup announce themselves to us. + **************************************************************************/ + +void broadcast_announce_request(struct subnet_record *subrec, struct work_record *work) +{ + pstring outbuf; + char *p; + + work->needannounce = True; + + DEBUG(3,("broadcast_announce_request: sending announce request for workgroup %s \ +to subnet %s\n", work->work_group, subrec->subnet_name)); + + bzero(outbuf,sizeof(outbuf)); + p = outbuf; + CVAL(p,0) = ANN_AnnouncementRequest; + p++; + + CVAL(p,0) = work->token; /* (local) Unique workgroup token id. */ + p++; + StrnCpy(p,myname,15); + strupper(p); + p = skip_string(p,1); + + send_mailslot(False, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf), + myname, 0x0, work->work_group,0x1e, subrec->bcast_ip, subrec->myip); +} + +/**************************************************************************** + Broadcast an announcement. + **************************************************************************/ + +static void send_announcement(struct subnet_record *subrec, int announce_type, + char *from_name, char *to_name, int to_type, struct in_addr to_ip, + time_t announce_interval, + char *server_name, int server_type, char *server_comment) +{ + pstring outbuf; + char *p; + + bzero(outbuf,sizeof(outbuf)); + p = outbuf+1; + + CVAL(outbuf,0) = announce_type; + + /* Announcement parameters. */ + CVAL(p,0) = updatecount; + SIVAL(p,1,announce_interval*1000); /* Milliseconds - despite the spec. */ + + StrnCpy(p+5,server_name,15); + strupper(p+5); + + CVAL(p,21) = lp_major_announce_version(); /* Major version. */ + CVAL(p,22) = lp_minor_announce_version(); /* Minor version. */ + + SIVAL(p,23,server_type & ~SV_TYPE_LOCAL_LIST_ONLY); + /* Browse version: got from NT/AS 4.00 - Value defined in smb.h (JHT). */ + SSVAL(p,27,BROWSER_ELECTION_VERSION); + SSVAL(p,29,BROWSER_CONSTANT); /* Browse signature. */ + + pstrcpy(p+31,server_comment); + p += 31; + p = skip_string(p,1); + + send_mailslot(False,BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf), + from_name, 0x0, to_name, to_type, to_ip, subrec->myip); +} + +/**************************************************************************** + We are a local master browser. Announce this to WORKGROUP<1e>. +****************************************************************************/ + +static void send_local_master_announcement(struct subnet_record *subrec, struct work_record *work, + struct server_record *servrec) +{ + /* Ensure we don't have the prohibited bit set. */ + uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY; + + DEBUG(3,("send_local_master_announcement: type %x for name %s on subnet %s for workgroup %s\n", + type, myname, subrec->subnet_name, work->work_group)); + + send_announcement(subrec, ANN_LocalMasterAnnouncement, + myname, /* From nbt name. */ + work->work_group, 0x1e, /* To nbt name. */ + subrec->bcast_ip, /* To ip. */ + work->announce_interval, /* Time until next announce. */ + myname, /* Name to announce. */ + type, /* Type field. */ + servrec->serv.comment); +} + +/**************************************************************************** + Announce the workgroup WORKGROUP to MSBROWSE<01>. +****************************************************************************/ + +static void send_workgroup_announcement(struct subnet_record *subrec, struct work_record *work) +{ + DEBUG(3,("send_workgroup_announcement: on subnet %s for workgroup %s\n", + subrec->subnet_name, work->work_group)); + + send_announcement(subrec, ANN_DomainAnnouncement, + myname, /* From nbt name. */ + MSBROWSE, 0x1, /* To nbt name. */ + subrec->bcast_ip, /* To ip. */ + work->announce_interval, /* Time until next announce. */ + work->work_group, /* Name to announce. */ + SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT, /* workgroup announce flags. */ + myname); /* From name as comment. */ +} + +/**************************************************************************** + Announce the given host to WORKGROUP<1d>. +****************************************************************************/ + +static void send_host_announcement(struct subnet_record *subrec, struct work_record *work, + struct server_record *servrec) +{ + /* Ensure we don't have the prohibited bits set. */ + uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY; + + DEBUG(3,("send_host_announcement: type %x for host %s on subnet %s for workgroup %s\n", + type, servrec->serv.name, subrec->subnet_name, work->work_group)); + + send_announcement(subrec, ANN_HostAnnouncement, + servrec->serv.name, /* From nbt name. */ + work->work_group, 0x1d, /* To nbt name. */ + subrec->bcast_ip, /* To ip. */ + work->announce_interval, /* Time until next announce. */ + servrec->serv.name, /* Name to announce. */ + type, /* Type field. */ + servrec->serv.comment); +} + +/**************************************************************************** + Announce a server record. + ****************************************************************************/ + +static void announce_server(struct subnet_record *subrec, struct work_record *work, + struct server_record *servrec) +{ + /* Only do domain announcements if we are a master and it's + our primary name we're being asked to announce. */ + + if (AM_LOCAL_MASTER_BROWSER(work) && strequal(myname,servrec->serv.name)) + { + send_local_master_announcement(subrec, work, servrec); + send_workgroup_announcement(subrec, work); + } + else + { + send_host_announcement(subrec, work, servrec); + } +} + +/**************************************************************************** + Go through all my registered names on all broadcast subnets and announce + them if the timeout requires it. + **************************************************************************/ + +void announce_my_server_names(time_t t) +{ + struct subnet_record *subrec; + + for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) + { + struct work_record *work = find_workgroup_on_subnet(subrec, myworkgroup); + + if(work) + { + struct server_record *servrec; + + if (work->needannounce) + { + /* Drop back to a max 3 minute announce. This is to prevent a + single lost packet from breaking things for too long. */ + + work->announce_interval = MIN(work->announce_interval, + CHECK_TIME_MIN_HOST_ANNCE*60); + work->lastannounce_time = t - (work->announce_interval+1); + work->needannounce = False; + } + + /* Announce every minute at first then progress to every 12 mins */ + if ((t - work->lastannounce_time) < work->announce_interval) + continue; + + if (work->announce_interval < (CHECK_TIME_MAX_HOST_ANNCE * 60)) + work->announce_interval += 60; + + work->lastannounce_time = t; + + for (servrec = work->serverlist; servrec; servrec = servrec->next) + { + if (is_myname(servrec->serv.name)) + announce_server(subrec, work, servrec); + } + } /* if work */ + } /* for subrec */ +} + +/* Announce timer. Moved into global static so it can be reset + when a machine becomes a local master browser. */ +static time_t announce_timer_last=0; + +/**************************************************************************** + Reset the announce_timer so that a local master browser announce will be done + immediately. + ****************************************************************************/ + +void reset_announce_timer() +{ + announce_timer_last = time(NULL) - (CHECK_TIME_MST_ANNOUNCE * 60); +} + +/**************************************************************************** + Announce myself as a local master browser to a domain master browser. + **************************************************************************/ + +void announce_myself_to_domain_master_browser(time_t t) +{ + struct subnet_record *subrec; + struct work_record *work; + + if(!we_are_a_wins_client()) + { + DEBUG(10,("announce_myself_to_domain_master_browser: no unicast subnet, ignoring.\n")); + return; + } + + if (!announce_timer_last) + announce_timer_last = t; + + if ((t-announce_timer_last) < (CHECK_TIME_MST_ANNOUNCE * 60)) + { + DEBUG(10,("announce_myself_to_domain_master_browser: t (%d) - last(%d) < %d\n", + t, announce_timer_last, CHECK_TIME_MST_ANNOUNCE * 60 )); + return; + } + + announce_timer_last = t; + + /* Look over all our broadcast subnets to see if any of them + has the state set as local master browser. */ + + for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) + { + for (work = subrec->workgrouplist; work; work = work->next) + { + if (AM_LOCAL_MASTER_BROWSER(work)) + { + DEBUG(4,( "announce_myself_to_domain_master_browser: I am a local master browser for \ +workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name)); + + /* Look in nmbd_browsersync.c for the rest of this code. */ + announce_and_sync_with_domain_master_browser(subrec, work); + } + } + } +} + +/**************************************************************************** +Announce all samba's server entries as 'gone'. +This must *only* be called on shutdown. +****************************************************************************/ + +void announce_my_servers_removed(void) +{ + struct subnet_record *subrec; + for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) + { + struct work_record *work; + for (work = subrec->workgrouplist; work; work = work->next) + { + struct server_record *servrec; + + work->announce_interval = 0; + for (servrec = work->serverlist; servrec; servrec = servrec->next) + { + if (!is_myname(servrec->serv.name)) + continue; + servrec->serv.type = 0; + if(AM_LOCAL_MASTER_BROWSER(work)) + send_local_master_announcement(subrec, work, servrec); + send_host_announcement(subrec, work, servrec); + } + } + } +} + +/**************************************************************************** + Do all the "remote" announcements. These are used to put ourselves + on a remote browse list. They are done blind, no checking is done to + see if there is actually a local master browser at the other end. + **************************************************************************/ + +void announce_remote(time_t t) +{ + char *s,*ptr; + static time_t last_time = 0; + pstring s2; + struct in_addr addr; + char *comment; + int stype = lp_default_server_announce(); + + if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL))) + return; + + last_time = t; + + s = lp_remote_announce(); + if (!*s) + return; + + comment = lp_serverstring(); + + for (ptr=s; next_token(&ptr,s2,NULL); ) + { + /* The entries are of the form a.b.c.d/WORKGROUP with + WORKGROUP being optional */ + char *wgroup; + int i; + + wgroup = strchr(s2,'/'); + if (wgroup) + *wgroup++ = 0; + if (!wgroup || !*wgroup) + wgroup = myworkgroup; + + addr = *interpret_addr2(s2); + + /* Announce all our names including aliases */ + /* Give the ip address as the address of our first + broadcast subnet. */ + + for(i=0; my_netbios_names[i]; i++) + { + char *name = my_netbios_names[i]; + + DEBUG(5,("announce_remote: Doing remote announce for server %s to IP %s.\n", + name, inet_ntoa(addr) )); + + send_announcement(FIRST_SUBNET, ANN_HostAnnouncement, + name, /* From nbt name. */ + wgroup, 0x1e, /* To nbt name. */ + addr, /* To ip. */ + REMOTE_ANNOUNCE_INTERVAL, /* Time until next announce. */ + name, /* Name to announce. */ + stype, /* Type field. */ + comment); + } + } +} + +/**************************************************************************** + Implement the 'remote browse sync' feature Andrew added. + These are used to put our browse lists into remote browse lists. + **************************************************************************/ + +void browse_sync_remote(time_t t) +{ + char *s,*ptr; + static time_t last_time = 0; + pstring s2; + struct in_addr addr; + struct work_record *work; + pstring outbuf; + char *p; + + if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL))) + return; + + last_time = t; + + s = lp_remote_browse_sync(); + if (!*s) + return; + + /* + * We only do this if we are the local master browser + * for our workgroup on the firsst subnet. + */ + + if((work = find_workgroup_on_subnet(FIRST_SUBNET, myworkgroup)) == NULL) + { + DEBUG(0,("browse_sync_remote: Cannot find workgroup %s on subnet %s\n", + myworkgroup, FIRST_SUBNET->subnet_name )); + return; + } + + if(!AM_LOCAL_MASTER_BROWSER(work)) + { + DEBUG(5,("browse_sync_remote: We can only do this if we are a local master browser \ +for workgroup %s on subnet %s.\n", myworkgroup, FIRST_SUBNET->subnet_name )); + return; + } + + bzero(outbuf,sizeof(outbuf)); + p = outbuf; + CVAL(p,0) = ANN_MasterAnnouncement; + p++; + + StrnCpy(p,myname,15); + strupper(p); + p = skip_string(p,1); + + for (ptr=s; next_token(&ptr,s2,NULL); ) + { + /* The entries are of the form a.b.c.d */ + addr = *interpret_addr2(s2); + + DEBUG(5,("announce_remote: Doing remote browse sync announce for server %s to IP %s.\n", + myname, inet_ntoa(addr) )); + + send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf), + myname, 0x0, "*", 0x0, addr, FIRST_SUBNET->myip); + } +} -- cgit