source: trunk/samba/source/nmbd/nmbd_sendannounce.c @ 26

Last change on this file since 26 was 26, checked in by Paul Smedley, 14 years ago

Updated source to 3.0.25rc1

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