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