home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / samba-1.9.18p7.tar.gz / samba-1.9.18p7.tar / samba-1.9.18p7 / source / nmbd_become_lmb.c < prev    next >
C/C++ Source or Header  |  1998-05-12  |  21KB  |  571 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-1998
  6.    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
  7.    Copyright (C) Jeremy Allison 1994-1998
  8.    
  9.    This program is free software; you can redistribute it and/or modify
  10.    it under the terms of the GNU General Public License as published by
  11.    the Free Software Foundation; either version 2 of the License, or
  12.    (at your option) any later version.
  13.    
  14.    This program is distributed in the hope that it will be useful,
  15.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.    GNU General Public License for more details.
  18.    
  19.    You should have received a copy of the GNU General Public License
  20.    along with this program; if not, write to the Free Software
  21.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22.    
  23. */
  24.  
  25. #include "includes.h"
  26.  
  27. extern int DEBUGLEVEL;
  28. extern pstring scope;
  29. extern pstring myname;
  30.  
  31. extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
  32.  
  33. /*******************************************************************
  34.  Utility function to add a name to the unicast subnet, or add in
  35.  our IP address if it already exists.
  36. ******************************************************************/
  37.  
  38. void insert_permanent_name_into_unicast( struct subnet_record *subrec, 
  39.                                                 struct nmb_name *nmbname, uint16 nb_type )
  40. {
  41.   struct name_record *namerec;
  42.  
  43.   if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) == NULL)
  44.   {
  45.     /* The name needs to be created on the unicast subnet. */
  46.     add_name_to_subnet( unicast_subnet, nmbname->name, nmbname->name_type,
  47.                         nb_type, PERMANENT_TTL, PERMANENT_NAME, 1, &subrec->myip);
  48.   }
  49.   else
  50.   {
  51.     /* The name already exists on the unicast subnet. Add our local
  52.        IP for the given broadcast subnet to the name. */
  53.     add_ip_to_name_record( namerec, subrec->myip);
  54.   }
  55. }
  56.  
  57. /*******************************************************************
  58.  Utility function to remove a name from the unicast subnet.
  59. ******************************************************************/
  60.  
  61. static void remove_permanent_name_from_unicast( struct subnet_record *subrec,
  62.                                                 struct nmb_name *nmbname )
  63. {
  64.   struct name_record *namerec;
  65.  
  66.   if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) != NULL)
  67.   {
  68.     /* Remove this broadcast subnet IP address from the name. */
  69.     remove_ip_from_name_record( namerec, subrec->myip);
  70.     if(namerec->num_ips == 0)
  71.       remove_name_from_namelist( unicast_subnet, namerec);
  72.   }
  73. }
  74.  
  75. /*******************************************************************
  76.  Utility function always called to set our workgroup and server
  77.  state back to potential browser, or none.
  78. ******************************************************************/
  79.  
  80. static void reset_workgroup_state( struct subnet_record *subrec, char *workgroup_name )
  81. {
  82.   struct work_record *work;
  83.   struct server_record *servrec;
  84.   struct nmb_name nmbname;
  85.  
  86.   if((work = find_workgroup_on_subnet( subrec, workgroup_name)) == NULL)
  87.   {
  88.     DEBUG(0,("reset_workgroup_state: Error - cannot find workgroup %s on \
  89. subnet %s.\n", workgroup_name, subrec->subnet_name ));
  90.     return;
  91.   }
  92.  
  93.   if((servrec = find_server_in_workgroup( work, myname)) == NULL)
  94.   {
  95.     DEBUG(0,("reset_workgroup_state: Error - cannot find server %s \
  96. in workgroup %s on subnet %s\n",
  97.        myname, work->work_group, subrec->subnet_name));
  98.     work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
  99.     return;
  100.   }
  101.  
  102.   /* Update our server status - remove any master flag and replace
  103.    it with the potential browser flag. */
  104.   servrec->serv.type &= ~SV_TYPE_MASTER_BROWSER;
  105.   servrec->serv.type |= (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0);
  106.  
  107.   /* Tell the namelist writer to write out a change. */
  108.   subrec->work_changed = True;
  109.  
  110.   /* Reset our election flags. */
  111.   work->ElectionCriterion &= ~0x4;
  112.  
  113.   work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
  114.  
  115.   /* Forget who the local master browser was for
  116.      this workgroup. */
  117.  
  118.   set_workgroup_local_master_browser_name( work, "");
  119.  
  120.   /*
  121.    * Ensure the IP address of this subnet is not registered as one
  122.    * of the IP addresses of the WORKGROUP<1d> name on the unicast
  123.    * subnet. This undoes what we did below when we became a local
  124.    * master browser.
  125.    */
  126.  
  127.   make_nmb_name(&nmbname, work->work_group, 0x1d, scope);
  128.  
  129.   remove_permanent_name_from_unicast( subrec, &nmbname);
  130.  
  131. }
  132.  
  133. /*******************************************************************
  134.   Unbecome the local master browser name release success function.
  135. ******************************************************************/
  136.  
  137. void unbecome_local_master_success(struct subnet_record *subrec,
  138.                              struct userdata_struct *userdata,
  139.                              struct nmb_name *released_name,
  140.                              struct in_addr released_ip)
  141.   DEBUG(3,("unbecome_local_master_success: released name %s.\n",
  142.              namestr(released_name)));
  143.  
  144.   /* Now reset the workgroup and server state. */
  145.   reset_workgroup_state( subrec, released_name->name );
  146.  
  147.   DEBUG(0,("\n%s *****   Samba name server %s has stopped being a local master browser for workgroup %s \
  148. on subnet %s *****\n\n", timestring(), myname, released_name->name, subrec->subnet_name));
  149.  
  150. }
  151.  
  152. /*******************************************************************
  153.   Unbecome the local master browser name release fail function.
  154. ******************************************************************/
  155.  
  156. void unbecome_local_master_fail(struct subnet_record *subrec, struct response_record *rrec,
  157.                        struct nmb_name *fail_name)
  158. {
  159.   struct name_record *namerec;
  160.  
  161.   DEBUG(0,("unbecome_local_master_fail: failed to release name %s. \
  162. Removing from namelist anyway.\n", namestr(fail_name)));
  163.  
  164.   /* Do it anyway. */
  165.   namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
  166.   if(namerec)
  167.     remove_name_from_namelist(subrec, namerec);
  168.  
  169.   /* Now reset the workgroup and server state. */
  170.   reset_workgroup_state( subrec, fail_name->name );
  171.  
  172.   DEBUG(0,("\n%s *****   Samba name server %s has stopped being a local master browser for workgroup %s \
  173. on subnet %s *****\n\n", timestring(), myname, fail_name->name, subrec->subnet_name));
  174.  
  175. }
  176.  
  177. /*******************************************************************
  178.  Utility function to remove the WORKGROUP<1d> name called by both
  179.  success and fail of releasing the MSBROWSE name.
  180. ******************************************************************/
  181.  
  182. void release_1d_name( struct subnet_record *subrec, char *workgroup_name)
  183. {
  184.   struct nmb_name nmbname;
  185.   struct name_record *namerec;
  186.  
  187.   make_nmb_name(&nmbname, workgroup_name, 0x1d, scope);
  188.   if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL)
  189.   {
  190.     release_name(subrec, namerec,
  191.                  unbecome_local_master_success,
  192.                  unbecome_local_master_fail,
  193.                  NULL);
  194.   }
  195. }
  196.  
  197. /*******************************************************************
  198.  Unbecome the local master browser MSBROWSE name release success function.
  199. ******************************************************************/
  200.  
  201. static void release_msbrowse_name_success(struct subnet_record *subrec,
  202.                       struct userdata_struct *userdata,
  203.                       struct nmb_name *released_name,
  204.                       struct in_addr released_ip)
  205. {
  206.   DEBUG(4,("release_msbrowse_name_success: Released name %s on subnet %s\n.",
  207.            namestr(released_name), subrec->subnet_name ));
  208.  
  209.   /* Remove the permanent MSBROWSE name added into the unicast subnet. */
  210.   remove_permanent_name_from_unicast( subrec, released_name);
  211.  
  212.   release_1d_name( subrec, userdata->data );
  213. }
  214.  
  215. /*******************************************************************
  216.  Unbecome the local master browser MSBROWSE name release fail function.
  217. ******************************************************************/
  218.  
  219. static void release_msbrowse_name_fail( struct subnet_record *subrec, 
  220.                        struct response_record *rrec,
  221.                        struct nmb_name *fail_name)
  222. {
  223.   struct userdata_struct *userdata = rrec->userdata;
  224.   struct name_record *namerec;
  225.  
  226.   DEBUG(4,("release_msbrowse_name_fail: Failed to release name %s on subnet %s\n.",
  227.            namestr(fail_name), subrec->subnet_name ));
  228.  
  229.   /* Release the name anyway. */
  230.   namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
  231.   if(namerec)
  232.     remove_name_from_namelist(subrec, namerec);
  233.  
  234.   /* Remove the permanent MSBROWSE name added into the unicast subnet. */
  235.   remove_permanent_name_from_unicast( subrec, fail_name);
  236.  
  237.   release_1d_name( subrec, userdata->data );
  238. }
  239.  
  240. /*******************************************************************
  241.   Unbecome the local master browser.
  242. ******************************************************************/
  243.  
  244. void unbecome_local_master_browser(struct subnet_record *subrec, struct work_record *work)
  245. {
  246.   struct server_record *servrec;
  247.   struct name_record *namerec;
  248.   struct nmb_name nmbname;
  249.   struct userdata_struct *userdata;
  250.  
  251.   /* Sanity check. */
  252.  
  253.   DEBUG(2,("unbecome_local_master_browser: unbecoming local master for workgroup %s \
  254. on subnet %s\n",work->work_group, subrec->subnet_name));
  255.   
  256.   if((servrec = find_server_in_workgroup( work, myname)) == NULL)
  257.   {
  258.     DEBUG(0,("unbecome_local_master_browser: Error - cannot find server %s \
  259. in workgroup %s on subnet %s\n",
  260.        myname, work->work_group, subrec->subnet_name));
  261.     work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
  262.     return;
  263.   }
  264.   
  265.   /* Set the state to unbecoming. */
  266.   work->mst_state = MST_UNBECOMING_MASTER;
  267.  
  268.   /* Setup the userdata for the MSBROWSE name release. */
  269.   if((userdata = (struct userdata_struct *)malloc( sizeof(struct userdata_struct) + sizeof(fstring)+1)) == NULL)
  270.   {
  271.     DEBUG(0,("unbecome_local_master_browser: malloc fail.\n"));
  272.     return;
  273.   }
  274.  
  275.   userdata->copy_fn = NULL;
  276.   userdata->free_fn = NULL;
  277.   userdata->userdata_len = strlen(work->work_group)+1;
  278.   pstrcpy(userdata->data, work->work_group);
  279.  
  280.   /* Deregister any browser names we may have. */
  281.   make_nmb_name(&nmbname, MSBROWSE, 0x1, scope);
  282.   if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL)
  283.   {
  284.     release_name(subrec, namerec,
  285.                  release_msbrowse_name_success,
  286.                  release_msbrowse_name_fail,
  287.                  userdata);
  288.   }
  289.  
  290.   free((char *)userdata);
  291. }
  292.  
  293. /****************************************************************************
  294.   Success in registering the WORKGROUP<1d> name.
  295.   We are now *really* a local master browser.
  296.   ****************************************************************************/
  297.  
  298. static void become_local_master_stage2(struct subnet_record *subrec,
  299.                                         struct userdata_struct *userdata,
  300.                                         struct nmb_name *registered_name,
  301.                                         uint16 nb_flags,
  302.                                         int ttl, struct in_addr registered_ip)
  303. {
  304.   int i = 0;
  305.   struct server_record *sl;
  306.   struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
  307.   struct server_record *servrec;
  308.  
  309.   if(!work)
  310.   {
  311.     DEBUG(0,("become_local_master_stage2: Error - cannot find \
  312. workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
  313.     return;
  314.   }
  315.  
  316.   if((servrec = find_server_in_workgroup( work, myname)) == NULL)
  317.   {
  318.     DEBUG(0,("become_local_master_stage2: Error - cannot find server %s \
  319. in workgroup %s on subnet %s\n",
  320.        myname, registered_name->name, subrec->subnet_name));
  321.     work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
  322.     return;
  323.   }
  324.   
  325.   DEBUG(3,("become_local_master_stage2: registered as master browser for workgroup %s \
  326. on subnet %s\n", work->work_group, subrec->subnet_name));
  327.  
  328.   work->mst_state = MST_BROWSER; /* registering WORKGROUP(1d) succeeded */
  329.  
  330.   /* update our server status */
  331.   servrec->serv.type |= SV_TYPE_MASTER_BROWSER;
  332.   servrec->serv.type &= ~SV_TYPE_POTENTIAL_BROWSER;
  333.  
  334.   /* Tell the namelist writer to write out a change. */
  335.   subrec->work_changed = True;
  336.  
  337.   /* Add this name to the workgroup as local master browser. */
  338.   set_workgroup_local_master_browser_name( work, myname);
  339.  
  340.   /* Count the number of servers we have on our list. If it's
  341.      less than 10 (just a heuristic) request the servers
  342.      to announce themselves.
  343.    */
  344.   for( sl = work->serverlist; sl != NULL; sl = sl->next)
  345.     i++;
  346.  
  347.   if (i < 10)
  348.   {
  349.     /* Ask all servers on our local net to announce to us. */
  350.     broadcast_announce_request(subrec, work);
  351.   }
  352.  
  353.   /*
  354.    * Now we are a local master on a broadcast subnet, we need to add
  355.    * the WORKGROUP<1d> name to the unicast subnet so that we can answer
  356.    * unicast requests sent to this name. We can create this name directly on
  357.    * the unicast subnet as a WINS server always returns true when registering
  358.    * this name, and discards the registration. We use the number of IP
  359.    * addresses registered to this name as a reference count, as we
  360.    * remove this broadcast subnet IP address from it when we stop becoming a local
  361.    * master browser for this broadcast subnet.
  362.    */
  363.  
  364.   insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
  365.  
  366.   /* Reset the announce master browser timer so that we try and tell a domain
  367.      master browser as soon as possible that we are a local master browser. */
  368.   reset_announce_timer();
  369.  
  370.   DEBUG(0,("\n%s *****   Samba name server %s is now a local master browser for workgroup %s \
  371. on subnet %s *****\n\n", timestring(), myname, work->work_group, subrec->subnet_name));
  372.  
  373. }
  374.  
  375. /****************************************************************************
  376.   Failed to register the WORKGROUP<1d> name.
  377.   ****************************************************************************/
  378. static void become_local_master_fail2(struct subnet_record *subrec,
  379.                                       struct response_record *rrec,
  380.                                       struct nmb_name *fail_name)
  381. {
  382.   struct work_record *work = find_workgroup_on_subnet( subrec, fail_name->name);
  383.  
  384.   DEBUG(0,("become_local_master_fail2: failed to register name %s on subnet %s. \
  385. Failed to become a local master browser.\n", namestr(fail_name), subrec->subnet_name));
  386.  
  387.   if(!work)
  388.   {
  389.     DEBUG(0,("become_local_master_fail2: Error - cannot find \
  390. workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
  391.     return;
  392.   }
  393.  
  394.   /* Roll back all the way by calling unbecome_local_master_browser(). */
  395.   unbecome_local_master_browser(subrec, work);
  396. }
  397.  
  398. /****************************************************************************
  399.   Success in registering the MSBROWSE name.
  400.   ****************************************************************************/
  401.  
  402. static void become_local_master_stage1(struct subnet_record *subrec,
  403.                                         struct userdata_struct *userdata,
  404.                                         struct nmb_name *registered_name,
  405.                                         uint16 nb_flags,
  406.                                         int ttl, struct in_addr registered_ip)
  407. {
  408.   char *work_name = userdata->data;
  409.   struct work_record *work = find_workgroup_on_subnet( subrec, work_name);
  410.  
  411.   if(!work)
  412.   {
  413.     DEBUG(0,("become_local_master_stage1: Error - cannot find \
  414. workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
  415.     return;
  416.   }
  417.  
  418.   DEBUG(3,("become_local_master_stage1: go to stage 2: register the %s<1d> name.\n",
  419.             work->work_group));
  420.  
  421.   work->mst_state = MST_MSB; /* Registering MSBROWSE was successful. */
  422.  
  423.   /*
  424.    * We registered the MSBROWSE name on a broadcast subnet, now need to add
  425.    * the MSBROWSE name to the unicast subnet so that we can answer
  426.    * unicast requests sent to this name. We create this name directly on
  427.    * the unicast subnet.
  428.    */
  429.  
  430.   insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
  431.  
  432.   /* Attempt to register the WORKGROUP<1d> name. */
  433.   register_name(subrec, work->work_group,0x1d,samba_nb_type,
  434.                 become_local_master_stage2,
  435.                 become_local_master_fail2,
  436.                 NULL);
  437. }
  438.  
  439. /****************************************************************************
  440.   Failed to register the MSBROWSE name.
  441.   ****************************************************************************/
  442.  
  443. static void become_local_master_fail1(struct subnet_record *subrec,
  444.                                       struct response_record *rrec,
  445.                                       struct nmb_name *fail_name)
  446. {
  447.   char *work_name = rrec->userdata->data;
  448.   struct work_record *work = find_workgroup_on_subnet(subrec, work_name);
  449.   struct server_record *servrec;
  450.  
  451.   if(!work)
  452.   {
  453.     DEBUG(0,("become_local_master_fail1: Error - cannot find \
  454. workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
  455.     return;
  456.   }
  457.  
  458.   if((servrec = find_server_in_workgroup(work, myname)) == NULL)
  459.   {
  460.     DEBUG(0,("become_local_master_fail1: Error - cannot find server %s \
  461. in workgroup %s on subnet %s\n",
  462.        myname, work->work_group, subrec->subnet_name));
  463.     return;
  464.   }
  465.  
  466.   reset_workgroup_state( subrec, work->work_group );
  467.  
  468.   DEBUG(0,("become_local_master_fail1: Failed to become a local master browser for \
  469. workgroup %s on subnet %s. Couldn't register name %s.\n",
  470.        work->work_group, subrec->subnet_name, namestr(fail_name)));
  471. }
  472.  
  473. /******************************************************************
  474.   Become the local master browser on a subnet.
  475.   This gets called if we win an election on this subnet.
  476.  
  477.   Stage 1: mst_state was MST_POTENTIAL - go to MST_BACK register ^1^2__MSBROWSE__^2^1.
  478.   Stage 2: mst_state was MST_BACKUP  - go to MST_MSB  and register WORKGROUP<1d>.
  479.   Stage 3: mst_state was MST_MSB  - go to MST_BROWSER.
  480. ******************************************************************/
  481.  
  482. void become_local_master_browser(struct subnet_record *subrec, struct work_record *work)
  483. {
  484.   struct server_record *servrec;
  485.   struct userdata_struct *userdata;
  486.  
  487.   /* Sanity check. */
  488.   if (!lp_local_master())
  489.   { 
  490.     DEBUG(0,("become_local_master_browser: Samba not configured as a local master browser.\n"));
  491.     return;
  492.   }
  493.  
  494.   if(!AM_POTENTIAL_MASTER_BROWSER(work))
  495.   {
  496.     DEBUG(2,("become_local_master_browser: Awaiting potential browser state. Current state is %d\n",
  497.               work->mst_state ));
  498.     return;
  499.   }
  500.  
  501.   if((servrec = find_server_in_workgroup( work, myname)) == NULL)
  502.   {
  503.     DEBUG(0,("become_local_master_browser: Error - cannot find server %s \
  504. in workgroup %s on subnet %s\n",
  505.        myname, work->work_group, subrec->subnet_name));
  506.     return;
  507.   }
  508.  
  509.   DEBUG(2,("become_local_master_browser: Starting to become a master browser for workgroup \
  510. %s on subnet %s\n", work->work_group, subrec->subnet_name));
  511.   
  512.   DEBUG(3,("become_local_master_browser: first stage - attempt to register ^1^2__MSBROWSE__^2^1\n"));
  513.   work->mst_state = MST_BACKUP; /* an election win was successful */
  514.  
  515.   work->ElectionCriterion |= 0x5;
  516.  
  517.   /* Tell the namelist writer to write out a change. */
  518.   subrec->work_changed = True;
  519.  
  520.   /* Setup the userdata_struct. */
  521.   if((userdata = (struct userdata_struct *)malloc(sizeof(struct userdata_struct) + sizeof(fstring)+1)) == NULL)
  522.   {
  523.     DEBUG(0,("become_local_master_browser: malloc fail.\n"));
  524.     return;
  525.   }
  526.  
  527.   userdata->copy_fn = NULL;
  528.   userdata->free_fn = NULL;
  529.   userdata->userdata_len = strlen(work->work_group)+1;
  530.   pstrcpy(userdata->data, work->work_group);
  531.  
  532.   /* Register the special browser group name. */
  533.   register_name(subrec, MSBROWSE, 0x01, samba_nb_type|NB_GROUP,
  534.                 become_local_master_stage1,
  535.                 become_local_master_fail1,
  536.                 userdata);
  537.  
  538.   free((char *)userdata);
  539. }
  540.  
  541. /***************************************************************
  542.  Utility function to set the local master browser name. Does
  543.  some sanity checking as old versions of Samba seem to sometimes
  544.  say that the master browser name for a workgroup is the same
  545.  as the workgroup name.
  546. ****************************************************************/
  547.  
  548. void set_workgroup_local_master_browser_name( struct work_record *work, char *newname)
  549. {
  550.   DEBUG(5,("set_workgroup_local_master_browser_name: setting local master name to '%s' \
  551. for workgroup %s.\n", newname, work->work_group ));
  552.  
  553. #if 0
  554.   /*
  555.    * Apparently some sites use the workgroup name as the local
  556.    * master browser name. Arrrrggghhhhh ! (JRA).
  557.    */
  558.   if(strequal( work->work_group, newname))
  559.   {
  560.     DEBUG(5, ("set_workgroup_local_master_browser_name: Refusing to set \
  561. local_master_browser_name for workgroup %s to workgroup name.\n",
  562.          work->work_group ));
  563.     return;
  564.   }
  565. #endif
  566.  
  567.   StrnCpy(work->local_master_browser_name, newname,
  568.             sizeof(work->local_master_browser_name)-1);
  569. }
  570.