first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[bbaumbach/samba-autobuild/.git] / source3 / nmbd / nmbd_sendannounce.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    SMB Version handling
10    Copyright (C) John H Terpstra 1995-1998
11    
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 2 of the License, or
15    (at your option) any later version.
16    
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21    
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software
24    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25    
26 */
27
28 #include "includes.h"
29
30 extern int DEBUGLEVEL;
31 extern pstring global_myname;
32 extern fstring global_myworkgroup;
33 extern char **my_netbios_names;
34 extern int  updatecount;
35 extern BOOL found_lm_clients;
36
37 /****************************************************************************
38  Send a browser reset packet.
39 **************************************************************************/
40
41 void send_browser_reset(int reset_type, char *to_name, int to_type, struct in_addr to_ip)
42 {
43   pstring outbuf;
44   char *p;
45
46   DEBUG(3,("send_browser_reset: sending reset request type %d to %s<%02x> IP %s.\n",
47        reset_type, to_name, to_type, inet_ntoa(to_ip) ));
48
49   memset(outbuf,'\0',sizeof(outbuf));
50   p = outbuf;
51   CVAL(p,0) = ANN_ResetBrowserState;
52   p++;
53   CVAL(p,0) = reset_type;
54   p++;
55
56   send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
57                 global_myname, 0x0, to_name, to_type, to_ip, 
58                 FIRST_SUBNET->myip, DGRAM_PORT);
59 }
60
61 /****************************************************************************
62   Broadcast a packet to the local net requesting that all servers in this
63   workgroup announce themselves to us.
64   **************************************************************************/
65
66 void broadcast_announce_request(struct subnet_record *subrec, struct work_record *work)
67 {
68   pstring outbuf;
69   char *p;
70
71   work->needannounce = True;
72
73   DEBUG(3,("broadcast_announce_request: sending announce request for workgroup %s \
74 to subnet %s\n", work->work_group, subrec->subnet_name));
75
76   memset(outbuf,'\0',sizeof(outbuf));
77   p = outbuf;
78   CVAL(p,0) = ANN_AnnouncementRequest;
79   p++;
80
81   CVAL(p,0) = work->token; /* (local) Unique workgroup token id. */
82   p++;
83   StrnCpy(p,global_myname,15);
84   strupper(p);
85   p = skip_string(p,1);
86   
87   send_mailslot(False, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
88                 global_myname, 0x0, work->work_group,0x1e, subrec->bcast_ip, 
89                 subrec->myip, DGRAM_PORT);
90 }
91
92 /****************************************************************************
93   Broadcast an announcement.
94   **************************************************************************/
95
96 static void send_announcement(struct subnet_record *subrec, int announce_type,
97                               char *from_name, char *to_name, int to_type, struct in_addr to_ip,
98                               time_t announce_interval,
99                               char *server_name, int server_type, char *server_comment)
100 {
101   pstring outbuf;
102   char *p;
103
104   memset(outbuf,'\0',sizeof(outbuf));
105   p = outbuf+1;
106
107   CVAL(outbuf,0) = announce_type;
108
109   /* Announcement parameters. */
110   CVAL(p,0) = updatecount;
111   SIVAL(p,1,announce_interval*1000); /* Milliseconds - despite the spec. */
112
113   StrnCpy(p+5,server_name,15);
114   strupper(p+5);
115
116   CVAL(p,21) = lp_major_announce_version(); /* Major version. */
117   CVAL(p,22) = lp_minor_announce_version(); /* Minor version. */
118
119   SIVAL(p,23,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
120   /* Browse version: got from NT/AS 4.00  - Value defined in smb.h (JHT). */
121   SSVAL(p,27,BROWSER_ELECTION_VERSION);
122   SSVAL(p,29,BROWSER_CONSTANT); /* Browse signature. */
123
124   pstrcpy(p+31,server_comment);
125   p += 31;
126   p = skip_string(p,1);
127
128   send_mailslot(False,BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
129                 from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
130                 DGRAM_PORT);
131 }
132
133 /****************************************************************************
134   Broadcast a LanMan announcement.
135 **************************************************************************/
136
137 static void send_lm_announcement(struct subnet_record *subrec, int announce_type,
138                               char *from_name, char *to_name, int to_type, struct in_addr to_ip,
139                               time_t announce_interval,
140                               char *server_name, int server_type, char *server_comment)
141 {
142   pstring outbuf;
143   char *p=outbuf;
144
145   memset(outbuf,'\0',sizeof(outbuf));
146
147   SSVAL(p,0,announce_type);
148   SIVAL(p,2,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
149   CVAL(p,6) = lp_major_announce_version(); /* Major version. */
150   CVAL(p,7) = lp_minor_announce_version(); /* Minor version. */
151   SSVAL(p,8,announce_interval);            /* In seconds - according to spec. */
152
153   p += 10;
154   StrnCpy(p,server_name,15);
155   strupper(p);
156   p = skip_string(p,1);
157   pstrcpy(p,server_comment);
158   p = skip_string(p,1);
159
160   send_mailslot(False,LANMAN_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
161                 from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
162                 DGRAM_PORT);
163 }
164
165 /****************************************************************************
166  We are a local master browser. Announce this to WORKGROUP<1e>.
167 ****************************************************************************/
168
169 static void send_local_master_announcement(struct subnet_record *subrec, struct work_record *work,
170                                            struct server_record *servrec)
171 {
172   /* Ensure we don't have the prohibited bit set. */
173   uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
174
175   DEBUG(3,("send_local_master_announcement: type %x for name %s on subnet %s for workgroup %s\n",
176             type, global_myname, subrec->subnet_name, work->work_group));
177
178   send_announcement(subrec, ANN_LocalMasterAnnouncement,
179                     global_myname,                   /* From nbt name. */
180                     work->work_group, 0x1e,          /* To nbt name. */
181                     subrec->bcast_ip,                /* To ip. */
182                     work->announce_interval,         /* Time until next announce. */
183                     global_myname,                   /* Name to announce. */
184                     type,                            /* Type field. */
185                     servrec->serv.comment);
186 }
187
188 /****************************************************************************
189  Announce the workgroup WORKGROUP to MSBROWSE<01>.
190 ****************************************************************************/
191
192 static void send_workgroup_announcement(struct subnet_record *subrec, struct work_record *work)
193 {
194   DEBUG(3,("send_workgroup_announcement: on subnet %s for workgroup %s\n",
195             subrec->subnet_name, work->work_group));
196
197   send_announcement(subrec, ANN_DomainAnnouncement,
198                     global_myname,                   /* From nbt name. */
199                     MSBROWSE, 0x1,                   /* To nbt name. */
200                     subrec->bcast_ip,                /* To ip. */
201                     work->announce_interval,         /* Time until next announce. */
202                     work->work_group,                /* Name to announce. */
203                     SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT,  /* workgroup announce flags. */
204                     global_myname);                  /* From name as comment. */
205 }
206
207 /****************************************************************************
208  Announce the given host to WORKGROUP<1d>.
209 ****************************************************************************/
210
211 static void send_host_announcement(struct subnet_record *subrec, struct work_record *work,
212                                    struct server_record *servrec)
213 {
214   /* Ensure we don't have the prohibited bits set. */
215   uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
216
217   DEBUG(3,("send_host_announcement: type %x for host %s on subnet %s for workgroup %s\n",
218             type, servrec->serv.name, subrec->subnet_name, work->work_group));
219
220   send_announcement(subrec, ANN_HostAnnouncement,
221                     servrec->serv.name,              /* From nbt name. */
222                     work->work_group, 0x1d,          /* To nbt name. */
223                     subrec->bcast_ip,                /* To ip. */
224                     work->announce_interval,         /* Time until next announce. */
225                     servrec->serv.name,              /* Name to announce. */
226                     type,                            /* Type field. */
227                     servrec->serv.comment);
228 }
229
230 /****************************************************************************
231  Announce the given LanMan host
232 ****************************************************************************/
233
234 static void send_lm_host_announcement(struct subnet_record *subrec, struct work_record *work,
235                                    struct server_record *servrec, int lm_interval)
236 {
237   /* Ensure we don't have the prohibited bits set. */
238   uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
239
240   DEBUG(3,("send_lm_host_announcement: type %x for host %s on subnet %s for workgroup %s, ttl: %d\n",
241             type, servrec->serv.name, subrec->subnet_name, work->work_group, lm_interval));
242
243   send_lm_announcement(subrec, ANN_HostAnnouncement,
244                     servrec->serv.name,              /* From nbt name. */
245                     work->work_group, 0x00,          /* To nbt name. */
246                     subrec->bcast_ip,                /* To ip. */
247                     lm_interval,                     /* Time until next announce. */
248                     servrec->serv.name,              /* Name to announce. */
249                     type,                            /* Type field. */
250                     servrec->serv.comment);
251 }
252
253 /****************************************************************************
254   Announce a server record.
255   ****************************************************************************/
256
257 static void announce_server(struct subnet_record *subrec, struct work_record *work,
258                      struct server_record *servrec)
259 {
260   /* Only do domain announcements if we are a master and it's
261      our primary name we're being asked to announce. */
262
263   if (AM_LOCAL_MASTER_BROWSER(work) && strequal(global_myname,servrec->serv.name))
264   {
265     send_local_master_announcement(subrec, work, servrec);
266     send_workgroup_announcement(subrec, work);
267   }
268   else
269   {
270     send_host_announcement(subrec, work, servrec);
271   }
272 }
273
274 /****************************************************************************
275   Go through all my registered names on all broadcast subnets and announce
276   them if the timeout requires it.
277   **************************************************************************/
278
279 void announce_my_server_names(time_t t)
280 {
281   struct subnet_record *subrec;
282
283   for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
284   {
285     struct work_record *work = find_workgroup_on_subnet(subrec, global_myworkgroup);
286
287     if(work)
288     {
289       struct server_record *servrec;
290
291       if (work->needannounce)
292       {
293         /* Drop back to a max 3 minute announce. This is to prevent a
294            single lost packet from breaking things for too long. */
295
296         work->announce_interval = MIN(work->announce_interval,
297                                     CHECK_TIME_MIN_HOST_ANNCE*60);
298         work->lastannounce_time = t - (work->announce_interval+1);
299         work->needannounce = False;
300       }
301
302       /* Announce every minute at first then progress to every 12 mins */
303       if ((t - work->lastannounce_time) < work->announce_interval)
304         continue;
305
306       if (work->announce_interval < (CHECK_TIME_MAX_HOST_ANNCE * 60))
307         work->announce_interval += 60;
308
309       work->lastannounce_time = t;
310
311       for (servrec = work->serverlist; servrec; servrec = servrec->next)
312       {
313         if (is_myname(servrec->serv.name))
314           announce_server(subrec, work, servrec);
315       }
316     } /* if work */
317   } /* for subrec */
318 }
319
320 /****************************************************************************
321   Go through all my registered names on all broadcast subnets and announce
322   them as a LanMan server if the timeout requires it.
323 **************************************************************************/
324
325 void announce_my_lm_server_names(time_t t)
326 {
327   struct subnet_record *subrec;
328   static time_t last_lm_announce_time=0;
329   int announce_interval = lp_lm_interval();
330   int lm_announce = lp_lm_announce();
331
332   if ((announce_interval <= 0) || (lm_announce <= 0))
333   {
334     /* user absolutely does not want LM announcements to be sent. */
335     return;
336   }
337
338   if ((lm_announce >= 2) && (!found_lm_clients))
339   {
340     /* has been set to 2 (Auto) but no LM clients detected (yet). */
341     return;
342   }
343
344   /* Otherwise: must have been set to 1 (Yes), or LM clients *have*
345      been detected. */
346
347   for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
348   {
349     struct work_record *work = find_workgroup_on_subnet(subrec, global_myworkgroup);
350
351     if(work)
352     {
353       struct server_record *servrec;
354
355       if (last_lm_announce_time && ((t - last_lm_announce_time) < announce_interval ))
356         continue;
357
358       last_lm_announce_time = t;
359
360       for (servrec = work->serverlist; servrec; servrec = servrec->next)
361       {
362         if (is_myname(servrec->serv.name))
363           /* skipping equivalent of announce_server() */
364           send_lm_host_announcement(subrec, work, servrec, announce_interval);
365       }
366     } /* if work */
367   } /* for subrec */
368 }
369
370 /* Announce timer. Moved into global static so it can be reset
371    when a machine becomes a local master browser. */
372 static time_t announce_timer_last=0;
373
374 /****************************************************************************
375  Reset the announce_timer so that a local master browser announce will be done
376  immediately.
377  ****************************************************************************/
378
379 void reset_announce_timer(void)
380 {
381   announce_timer_last = time(NULL) - (CHECK_TIME_MST_ANNOUNCE * 60);
382 }
383
384 /****************************************************************************
385   Announce myself as a local master browser to a domain master browser.
386   **************************************************************************/
387
388 void announce_myself_to_domain_master_browser(time_t t)
389 {
390   struct subnet_record *subrec;
391   struct work_record *work;
392
393   if(!we_are_a_wins_client())
394   {
395     DEBUG(10,("announce_myself_to_domain_master_browser: no unicast subnet, ignoring.\n"));
396     return;
397   }
398
399   if (!announce_timer_last)
400     announce_timer_last = t;
401
402   if ((t-announce_timer_last) < (CHECK_TIME_MST_ANNOUNCE * 60))
403   {
404     DEBUG(10,("announce_myself_to_domain_master_browser: t (%d) - last(%d) < %d\n",
405               (int)t, (int)announce_timer_last, 
406               CHECK_TIME_MST_ANNOUNCE * 60 ));
407     return;
408   }
409
410   announce_timer_last = t;
411
412   /* Look over all our broadcast subnets to see if any of them
413      has the state set as local master browser. */
414
415   for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
416   {
417     for (work = subrec->workgrouplist; work; work = work->next)
418     {
419       if (AM_LOCAL_MASTER_BROWSER(work))
420       {
421         DEBUG(4,( "announce_myself_to_domain_master_browser: I am a local master browser for \
422 workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
423
424         /* Look in nmbd_browsersync.c for the rest of this code. */
425         announce_and_sync_with_domain_master_browser(subrec, work);
426       }
427     }
428   }
429 }
430
431 /****************************************************************************
432 Announce all samba's server entries as 'gone'.
433 This must *only* be called on shutdown.
434 ****************************************************************************/
435
436 void announce_my_servers_removed(void)
437 {
438   int announce_interval = lp_lm_interval();
439   int lm_announce = lp_lm_announce();
440   struct subnet_record *subrec; 
441
442   for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
443   {
444     struct work_record *work;
445     for (work = subrec->workgrouplist; work; work = work->next)
446     {
447       struct server_record *servrec;
448
449       work->announce_interval = 0;
450       for (servrec = work->serverlist; servrec; servrec = servrec->next)
451       {
452         if (!is_myname(servrec->serv.name))
453           continue;
454         servrec->serv.type = 0;
455         if(AM_LOCAL_MASTER_BROWSER(work))
456           send_local_master_announcement(subrec, work, servrec);
457         send_host_announcement(subrec, work, servrec);
458
459
460         if ((announce_interval <= 0) || (lm_announce <= 0))
461         {
462           /* user absolutely does not want LM announcements to be sent. */
463           continue;
464         }
465
466         if ((lm_announce >= 2) && (!found_lm_clients))
467         {
468           /* has been set to 2 (Auto) but no LM clients detected (yet). */
469           continue;
470         }
471
472         /* 
473          * lm announce was set or we have seen lm announcements, so do
474          * a lm announcement of host removed.
475          */
476
477         send_lm_host_announcement(subrec, work, servrec, 0);
478       }
479     }
480   }
481 }
482
483 /****************************************************************************
484   Do all the "remote" announcements. These are used to put ourselves
485   on a remote browse list. They are done blind, no checking is done to
486   see if there is actually a local master browser at the other end.
487   **************************************************************************/
488
489 void announce_remote(time_t t)
490 {
491   char *s,*ptr;
492   static time_t last_time = 0;
493   pstring s2;
494   struct in_addr addr;
495   char *comment;
496   int stype = lp_default_server_announce();
497
498   if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
499     return;
500
501   last_time = t;
502
503   s = lp_remote_announce();
504   if (!*s)
505     return;
506
507   comment = string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH);
508
509   for (ptr=s; next_token(&ptr,s2,NULL,sizeof(s2)); ) 
510   {
511     /* The entries are of the form a.b.c.d/WORKGROUP with 
512        WORKGROUP being optional */
513     char *wgroup;
514     int i;
515
516     wgroup = strchr(s2,'/');
517     if (wgroup)
518       *wgroup++ = 0;
519     if (!wgroup || !*wgroup)
520       wgroup = global_myworkgroup;
521
522     addr = *interpret_addr2(s2);
523     
524     /* Announce all our names including aliases */
525     /* Give the ip address as the address of our first
526        broadcast subnet. */
527
528     for(i=0; my_netbios_names[i]; i++) 
529     {
530       char *name = my_netbios_names[i];
531
532       DEBUG(5,("announce_remote: Doing remote announce for server %s to IP %s.\n",
533                  name, inet_ntoa(addr) ));
534
535       send_announcement(FIRST_SUBNET, ANN_HostAnnouncement,
536                     name,                      /* From nbt name. */
537                     wgroup, 0x1d,              /* To nbt name. */
538                     addr,                      /* To ip. */
539                     REMOTE_ANNOUNCE_INTERVAL,  /* Time until next announce. */
540                     name,                      /* Name to announce. */
541                     stype,                     /* Type field. */
542                     comment);
543     }
544   }
545 }
546
547 /****************************************************************************
548   Implement the 'remote browse sync' feature Andrew added.
549   These are used to put our browse lists into remote browse lists.
550   **************************************************************************/
551
552 void browse_sync_remote(time_t t)
553 {  
554   char *s,*ptr;
555   static time_t last_time = 0; 
556   pstring s2;
557   struct in_addr addr;
558   struct work_record *work;
559   pstring outbuf;
560   char *p;
561  
562   if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
563     return;
564    
565   last_time = t;
566
567   s = lp_remote_browse_sync();
568   if (!*s)
569     return;
570
571   /*
572    * We only do this if we are the local master browser
573    * for our workgroup on the firsst subnet.
574    */
575
576   if((work = find_workgroup_on_subnet(FIRST_SUBNET, global_myworkgroup)) == NULL)
577   {   
578     DEBUG(0,("browse_sync_remote: Cannot find workgroup %s on subnet %s\n",
579            global_myworkgroup, FIRST_SUBNET->subnet_name ));
580     return;
581   }   
582          
583   if(!AM_LOCAL_MASTER_BROWSER(work))
584   {
585     DEBUG(5,("browse_sync_remote: We can only do this if we are a local master browser \
586 for workgroup %s on subnet %s.\n", global_myworkgroup, FIRST_SUBNET->subnet_name ));
587     return;
588   } 
589
590   memset(outbuf,'\0',sizeof(outbuf));
591   p = outbuf;
592   CVAL(p,0) = ANN_MasterAnnouncement;
593   p++;
594
595   StrnCpy(p,global_myname,15);
596   strupper(p);
597   p = skip_string(p,1);
598
599   for (ptr=s; next_token(&ptr,s2,NULL,sizeof(s2)); ) 
600   {
601     /* The entries are of the form a.b.c.d */
602     addr = *interpret_addr2(s2);
603
604     DEBUG(5,("announce_remote: Doing remote browse sync announce for server %s to IP %s.\n",
605                  global_myname, inet_ntoa(addr) ));
606
607     send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
608           global_myname, 0x0, "*", 0x0, addr, FIRST_SUBNET->myip, DGRAM_PORT);
609   }
610 }