home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 July & August / Pcwk78a98.iso / Wtestowe / Clico / UNIX / SAMBA / SOURCE / SAMBA.TAR / samba-1.9.17 / source / nameannounce.c < prev    next >
C/C++ Source or Header  |  1997-07-31  |  16KB  |  529 lines

  1. /* 
  2.    Unix SMB/Netbios implementation.
  3.    Version 1.9.
  4.    NBT netbios routines and daemon - version 2
  5.    Copyright (C) Andrew Tridgell 1994-1997
  6.  
  7.    SMB Version handling
  8.    Copyright (C) John H Terpstra 1995-1997
  9.    
  10.    This program is free software; you can redistribute it and/or modify
  11.    it under the terms of the GNU General Public License as published by
  12.    the Free Software Foundation; either version 2 of the License, or
  13.    (at your option) any later version.
  14.    
  15.    This program is distributed in the hope that it will be useful,
  16.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.    GNU General Public License for more details.
  19.    
  20.    You should have received a copy of the GNU General Public License
  21.    along with this program; if not, write to the Free Software
  22.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23.    
  24.    Revision History:
  25.  
  26.    14 jan 96: lkcl@pires.co.uk
  27.    added multiple workgroup domain master support
  28.  
  29. */
  30.  
  31. #include "includes.h"
  32.  
  33. #define TEST_CODE
  34.  
  35. extern int DEBUGLEVEL;
  36. extern BOOL CanRecurse;
  37.  
  38. extern struct in_addr ipzero;
  39.  
  40. extern pstring myname;
  41. extern fstring myworkgroup;
  42. extern char **my_netbios_names;
  43.  
  44. extern int ClientDGRAM;
  45. extern int ClientNMB;
  46.  
  47. /* this is our domain/workgroup/server database */
  48. extern struct subnet_record *subnetlist;
  49.  
  50. extern int  updatecount;
  51. extern int  workgroup_count;
  52.  
  53. extern struct in_addr wins_ip;
  54.  
  55. extern pstring scope;
  56.  
  57. /****************************************************************************
  58.   send a announce request to the local net
  59.   **************************************************************************/
  60. void announce_request(struct work_record *work, struct in_addr ip)
  61. {
  62.   pstring outbuf;
  63.   char *p;
  64.  
  65.   if (!work) return;
  66.  
  67.   work->needannounce = True;
  68.  
  69.   DEBUG(2,("sending announce request to %s for workgroup %s\n",
  70.        inet_ntoa(ip),work->work_group));
  71.  
  72.   bzero(outbuf,sizeof(outbuf));
  73.   p = outbuf;
  74.   CVAL(p,0) = ANN_AnnouncementRequest;
  75.   p++;
  76.  
  77.   CVAL(p,0) = work->token; /* (local) unique workgroup token id */
  78.   p++;
  79.   StrnCpy(p,myname,16);
  80.   strupper(p);
  81.   p = skip_string(p,1);
  82.   
  83.   /* XXXX note: if we sent the announcement request to 0x1d instead
  84.      of 0x1e, then we could get the master browser to announce to
  85.      us instead of the members of the workgroup. wha-hey! */
  86.  
  87.   send_mailslot_reply(False, BROWSE_MAILSLOT,ClientDGRAM,
  88.               outbuf,PTR_DIFF(p,outbuf),
  89.               myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
  90. }
  91.  
  92.  
  93. /****************************************************************************
  94.   request an announcement
  95.   **************************************************************************/
  96. void do_announce_request(char *info, char *to_name, int announce_type, 
  97.              int from,
  98.              int to, struct in_addr dest_ip)
  99. {
  100.   pstring outbuf;
  101.   char *p;
  102.   
  103.   bzero(outbuf,sizeof(outbuf));
  104.   p = outbuf;
  105.   CVAL(p,0) = announce_type; 
  106.   p++;
  107.   
  108.   DEBUG(2,("sending announce type %d: info %s to %s - server %s(%x)\n",
  109.        announce_type, info, inet_ntoa(dest_ip),to_name,to));
  110.   
  111.   StrnCpy(p,info,16);
  112.   strupper(p);
  113.   p = skip_string(p,1);
  114.   
  115.   send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
  116.               outbuf,PTR_DIFF(p,outbuf),
  117.               myname,to_name,from,to,dest_ip,*iface_ip(dest_ip));
  118. }
  119.  
  120.  
  121. /****************************************************************************
  122.   find a server responsible for a workgroup, and sync browse lists
  123.   control ends up back here via response_name_query.
  124.   **************************************************************************/
  125. void sync_server(enum state_type state, char *serv_name, char *work_name, 
  126.          int name_type,
  127.                  struct subnet_record *d,
  128.          struct in_addr ip)
  129. {                     
  130.   /* with a domain master we can get the whole list (not local only list) */
  131.   BOOL local_only = (state != NAME_STATUS_DOM_SRV_CHK);
  132.  
  133.   add_browser_entry(serv_name, name_type, work_name, 0, d, ip, local_only);
  134.  
  135.   if (state == NAME_STATUS_DOM_SRV_CHK)
  136.   {
  137.     /* announce ourselves as a master browser to serv_name */
  138.     do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
  139.               0x20, 0, ip);
  140.   }
  141. }
  142.  
  143.  
  144. /****************************************************************************
  145.   send a host announcement packet
  146.   **************************************************************************/
  147. void do_announce_host(int command,
  148.         char *from_name, int from_type, struct in_addr from_ip,
  149.         char *to_name  , int to_type  , struct in_addr to_ip,
  150.         time_t announce_interval,
  151.         char *server_name, int server_type, char *server_comment)
  152. {
  153.     pstring outbuf;
  154.     char *p;
  155.  
  156.     bzero(outbuf,sizeof(outbuf));
  157.     p = outbuf+1;
  158.  
  159.     /* command type */
  160.     CVAL(outbuf,0) = command;
  161.  
  162.     /* announcement parameters */
  163.     CVAL(p,0) = updatecount;
  164.     SIVAL(p,1,announce_interval*1000); /* ms - despite the spec */
  165.  
  166.     StrnCpy(p+5,server_name,16);
  167.     strupper(p+5);
  168.  
  169.     CVAL(p,21) = lp_major_announce_version(); /* major version */
  170.     CVAL(p,22) = lp_minor_announce_version(); /* minor version */
  171.  
  172.     SIVAL(p,23,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
  173.     /* browse version: got from NT/AS 4.00  - Value defined in smb.h (JHT)*/
  174.     SSVAL(p,27,BROWSER_ELECTION_VERSION);
  175.     SSVAL(p,29,BROWSER_CONSTANT); /* browse signature */
  176.  
  177.     strcpy(p+31,server_comment);
  178.     p += 31;
  179.     p = skip_string(p,1);
  180.  
  181.     debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
  182.  
  183.     /* send the announcement */
  184.     send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,outbuf,
  185.                       PTR_DIFF(p,outbuf),
  186.                       from_name, to_name,
  187.                       from_type, to_type,
  188.                       to_ip, from_ip);
  189. }
  190.  
  191.  
  192. /****************************************************************************
  193. announce all samba's server entries as 'gone'.
  194. ****************************************************************************/
  195. void announce_my_servers_removed(void)
  196. {
  197.     struct subnet_record *d; 
  198.     for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
  199.     {
  200.         struct work_record *work;
  201.         for (work = d->workgrouplist; work; work = work->next)
  202.         {
  203.             struct server_record *s;
  204.             for (s = work->serverlist; s; s = s->next)
  205.             {
  206.                 if (!is_myname(s->serv.name)) continue;
  207.                 announce_server(d, work, s->serv.name, s->serv.comment, 0, 0);
  208.             }
  209.         }
  210.     }
  211. }
  212.  
  213.  
  214. /****************************************************************************
  215.   announce a server entry
  216.   ****************************************************************************/
  217. void announce_server(struct subnet_record *d, struct work_record *work,
  218.              char *name, char *comment, time_t ttl, int server_type)
  219. {
  220.     /* domain type cannot have anything in it that might confuse
  221.        a client into thinking that the domain is in fact a server.
  222.        (SV_TYPE_SERVER_UNIX, for example)
  223.      */
  224.     uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT;
  225.     BOOL wins_iface = ip_equal(d->bcast_ip, wins_ip);
  226.  
  227.     if(wins_iface)
  228.     {
  229.       DEBUG(0,("announce_server: error - announcement requested on WINS \
  230. interface for workgroup %s, name %s\n", work->work_group, name));
  231.       return;
  232.     }
  233.  
  234.     /* Only do domain announcements if we are a master and it's
  235.        our name we're being asked to announce. */
  236.     if (AM_MASTER(work) && strequal(myname,name))
  237.     {
  238.         DEBUG(3,("sending local master announce to %s for %s(1e)\n",
  239.                         inet_ntoa(d->bcast_ip),work->work_group));
  240.  
  241.         do_announce_host(ANN_LocalMasterAnnouncement,
  242.                         name            , 0x00, d->myip,
  243.                         work->work_group, 0x1e, d->bcast_ip,
  244.                         ttl,
  245.                         name, server_type, comment);
  246.  
  247.         DEBUG(3,("sending domain announce to %s for %s\n",
  248.                         inet_ntoa(d->bcast_ip),work->work_group));
  249.  
  250.         /* XXXX should we do a domain-announce-kill? */
  251.         if (server_type != 0)
  252.         {
  253.             do_announce_host(ANN_DomainAnnouncement,
  254.                         name    , 0x00, d->myip,
  255.                         MSBROWSE, 0x01, d->bcast_ip,
  256.                         ttl,
  257.                         work->work_group, server_type ? domain_type : 0,
  258.                         name);
  259.         }
  260.     }
  261.     else
  262.     {
  263.         DEBUG(3,("sending host announce to %s for %s(1d)\n",
  264.                         inet_ntoa(d->bcast_ip),work->work_group));
  265.  
  266.         do_announce_host(ANN_HostAnnouncement,
  267.                         name            , 0x00, d->myip,
  268.                         work->work_group, 0x1d, d->bcast_ip,
  269.                         ttl,
  270.                         name, server_type, comment);
  271.     }
  272. }
  273.  
  274. /****************************************************************************
  275.   construct a host announcement unicast
  276.   **************************************************************************/
  277. void announce_host(time_t t)
  278. {
  279.   struct subnet_record *d;
  280.   pstring comment;
  281.   char *my_name;
  282.  
  283.   StrnCpy(comment, lp_serverstring(), 43);
  284.  
  285.   my_name = *myname ? myname : "NoName";
  286.  
  287.   for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
  288.     {
  289.       struct work_record *work;
  290.       
  291.       for (work = d->workgrouplist; work; work = work->next)
  292.     {
  293.       uint32 stype = work->ServerType;
  294.       struct server_record *s;
  295.       
  296.       /* must work on the code that does announcements at up to
  297.          30 seconds later if a master browser sends us a request
  298.          announce.
  299.          */
  300.  
  301.       if (work->needannounce) {
  302.         /* drop back to a max 3 minute announce - this is to prevent a
  303.            single lost packet from stuffing things up for too long */
  304.         work->announce_interval = MIN(work->announce_interval,
  305.                       CHECK_TIME_MIN_HOST_ANNCE*60);
  306.         work->lastannounce_time = t - (work->announce_interval+1);
  307.       }
  308.       
  309.       /* announce every minute at first then progress to every 12 mins */
  310.       if (work->lastannounce_time && 
  311.           (t - work->lastannounce_time) < work->announce_interval)
  312.         continue;
  313.       
  314.       if (work->announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60) 
  315.         work->announce_interval += 60;
  316.       
  317.       work->lastannounce_time = t;
  318.       
  319.       for (s = work->serverlist; s; s = s->next) {
  320.         if (is_myname(s->serv.name)) { 
  321.               /* If we are any kind of browser or logon server, only 
  322.                  announce it for our primary name, not our aliases. */
  323.               if(!strequal(myname, s->serv.name))
  324.                 stype &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_POTENTIAL_BROWSER|
  325.                            SV_TYPE_DOMAIN_MASTER|SV_TYPE_DOMAIN_MEMBER);
  326.           announce_server(d,work,s->serv.name,comment,
  327.                 work->announce_interval,stype);
  328.         }
  329.       }
  330.       
  331.       if (work->needannounce)
  332.         {
  333.           work->needannounce = False;
  334.           break;
  335.           /* sorry: can't do too many announces. do some more later */
  336.         }
  337.     }
  338.     }
  339. }
  340.  
  341. /* Announce timer. Moved into global static so it can be reset
  342.    when a machine becomes a master browser. */
  343. static time_t announce_timer_last=0;
  344.  
  345. /****************************************************************************
  346.  Reset the announce_timer so that a master browser announce will be done
  347.  immediately.
  348.  ****************************************************************************/
  349.  
  350. void reset_announce_timer()
  351. {
  352.   announce_timer_last = time(NULL) - (CHECK_TIME_MST_ANNOUNCE * 60);
  353. }
  354.  
  355. /****************************************************************************
  356.   announce myself as a master to all other domain master browsers.
  357.  
  358.   this actually gets done in search_and_sync_workgroups() via the
  359.   NAME_QUERY_DOM_SRV_CHK command, if there is a response from the
  360.   name query initiated here.  see response_name_query()
  361.   **************************************************************************/
  362. void announce_master(time_t t)
  363. {
  364.   struct subnet_record *d;
  365.   struct work_record *work;
  366.   BOOL am_master = False; /* are we a master of some sort? :-) */
  367.  
  368.   if (!announce_timer_last) announce_timer_last = t;
  369.   if (t-announce_timer_last < CHECK_TIME_MST_ANNOUNCE * 60)
  370.     {
  371.       DEBUG(10,("announce_master: t (%d) - last(%d) < %d\n",
  372.                  t, announce_timer_last, CHECK_TIME_MST_ANNOUNCE * 60 ));
  373.       return;
  374.     }
  375.  
  376.   if(wins_subnet == NULL)
  377.     {
  378.       DEBUG(10,("announce_master: no wins subnet, ignoring.\n"));
  379.       return;
  380.     }
  381.  
  382.   announce_timer_last = t;
  383.  
  384.   for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
  385.     {
  386.       struct work_record *work;
  387.       for (work = d->workgrouplist; work; work = work->next)
  388.     {
  389.       if (AM_MASTER(work))
  390.         {
  391.           am_master = True;
  392.               DEBUG(4,( "announce_master: am_master = %d for \
  393. workgroup %s\n", am_master, work->work_group));
  394.         }
  395.     }
  396.     }
  397.  
  398.   if (!am_master) return; /* only proceed if we are a master browser */
  399.   
  400.   /* Note that we don't do this if we are domain master browser
  401.      and that we *only* do this on the WINS subnet. */
  402.  
  403.   /* Try and find our workgroup on the WINS subnet */
  404.   work = find_workgroupstruct(wins_subnet, myworkgroup, False);
  405.  
  406.   if (work)
  407.     {
  408.       char *name;
  409.       int   type;
  410.  
  411.         {
  412.           /* assume that the domain master browser we want to sync
  413.              with is our own domain.
  414.            */
  415.           name = work->work_group;
  416.           type = 0x1b;
  417.         }
  418.  
  419.       /* check the existence of a dmb for this workgroup, and if
  420.          one exists at the specified ip, sync with it and announce
  421.          ourselves as a master browser to it
  422.        */
  423.  
  424.       if (!lp_wins_support() && *lp_wins_server() )
  425.         {
  426.           DEBUG(4, ("Local Announce: find %s<%02x> from WINS server %s\n",
  427.                      name, type, lp_wins_server()));
  428.  
  429.           queue_netbios_pkt_wins(ClientNMB,
  430.                     NMB_QUERY,NAME_QUERY_DOM_SRV_CHK,
  431.                     name, type, 0,0,0,
  432.                     work->work_group,NULL,
  433.                     False, True, ipzero, ipzero);
  434.         }
  435.       else if(lp_wins_support()) 
  436.         {
  437.            /* We are the WINS server - query ourselves for the dmb name. */
  438.  
  439.            struct nmb_name netb_name;
  440.            struct subnet_record *d = 0;
  441.            struct name_record *nr = 0;
  442.  
  443.            make_nmb_name(&netb_name, name, type, scope);
  444.  
  445.            if ((nr = find_name_search(&d, &netb_name, FIND_WINS, ipzero)) == 0)
  446.              {
  447.                DEBUG(0, ("announce_master: unable to find domain master browser for workgroup %s \
  448. in our own WINS database.\n", work->work_group));
  449.                return;
  450.              }
  451.  
  452.            /* Check that this isn't one of our addresses (ie. we are not domain master
  453.               ourselves) */
  454.            if(ismyip(nr->ip_flgs[0].ip) || ip_equal(nr->ip_flgs[0].ip, ipzero))
  455.              {
  456.                DEBUG(4, ("announce_master: domain master ip found (%s) for workgroup %s \
  457. is one of our interfaces.\n", work->work_group, inet_ntoa(nr->ip_flgs[0].ip) ));
  458.                return;
  459.              }
  460.  
  461.            /* Issue a NAME_STATUS_DOM_SRV_CHK immediately - short circuit the
  462.               NAME_QUERY_DOM_SRV_CHK which is done only if we are talking to a 
  463.               remote WINS server. */
  464.  
  465.            DEBUG(4, ("announce_master: doing name status for %s<%02x> to domain master ip %s \
  466. for workgroup %s\n", name, type, inet_ntoa(nr->ip_flgs[0].ip), work->work_group ));
  467.  
  468.            queue_netbios_packet(wins_subnet, ClientNMB,
  469.                     NMB_QUERY,NAME_STATUS_DOM_SRV_CHK,
  470.                     name, type, 0,0,0,
  471.                     work->work_group,NULL,
  472.                     False, False, nr->ip_flgs[0].ip, nr->ip_flgs[0].ip);
  473.          }
  474.  
  475.     }
  476. }
  477.  
  478. /****************************************************************************
  479.   do all the "remote" announcements. These are used to put ourselves
  480.   on a remote browse list. They are done blind, no checking is done to
  481.   see if there is actually a browse master at the other end.
  482.   **************************************************************************/
  483. void announce_remote(time_t t)
  484. {
  485.   char *s,*ptr;
  486.   static time_t last_time = 0;
  487.   pstring s2;
  488.   struct in_addr addr;
  489.   char *comment,*workgroup;
  490.   int stype = lp_default_server_announce();
  491.  
  492.   if (last_time && t < last_time + REMOTE_ANNOUNCE_INTERVAL)
  493.     return;
  494.  
  495.   last_time = t;
  496.  
  497.   s = lp_remote_announce();
  498.   if (!*s) return;
  499.  
  500.   comment = lp_serverstring();
  501.   workgroup = myworkgroup;
  502.  
  503.   for (ptr=s; next_token(&ptr,s2,NULL); ) 
  504.   {
  505.     /* the entries are of the form a.b.c.d/WORKGROUP with 
  506.        WORKGROUP being optional */
  507.     char *wgroup;
  508.     int n;
  509.  
  510.     wgroup = strchr(s2,'/');
  511.     if (wgroup) *wgroup++ = 0;
  512.     if (!wgroup || !*wgroup)
  513.       wgroup = workgroup;
  514.  
  515.     addr = *interpret_addr2(s2);
  516.     
  517.     /* Announce all our names including aliases */
  518.     for (n=0; my_netbios_names[n]; n++) 
  519.     {
  520.       char *name = my_netbios_names[n];
  521.       do_announce_host(ANN_HostAnnouncement,name,0x20,*iface_ip(addr),
  522.              wgroup,0x1e,addr,
  523.              REMOTE_ANNOUNCE_INTERVAL,
  524.              name,stype,comment);    
  525.     }
  526.   }
  527.  
  528. }
  529.