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