s3: nmbd: Stop nmbd network announce storm.
[samba.git] / source3 / nmbd / nmbd_sendannounce.c
index a74dd99196f69b8539a26ca5a8a4051b6a2b080b..a9cdf1c5a5833a8bd146ea084be9ed3cfc8fa75c 100644 (file)
@@ -10,7 +10,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
 */
 
 #include "includes.h"
+#include "../librpc/gen_ndr/svcctl.h"
+#include "nmbd/nmbd.h"
 
 extern int  updatecount;
-extern BOOL found_lm_clients;
+extern bool found_lm_clients;
 
 /****************************************************************************
  Send a browser reset packet.
@@ -35,7 +36,7 @@ extern BOOL found_lm_clients;
 
 void send_browser_reset(int reset_type, const char *to_name, int to_type, struct in_addr to_ip)
 {
-       pstring outbuf;
+       char outbuf[1024];
        char *p;
 
        DEBUG(3,("send_browser_reset: sending reset request type %d to %s<%02x> IP %s.\n",
@@ -49,7 +50,7 @@ void send_browser_reset(int reset_type, const char *to_name, int to_type, struct
        p++;
 
        send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
-               global_myname(), 0x0, to_name, to_type, to_ip, 
+               lp_netbios_name(), 0x0, to_name, to_type, to_ip,
                FIRST_SUBNET->myip, DGRAM_PORT);
 }
 
@@ -60,7 +61,7 @@ void send_browser_reset(int reset_type, const char *to_name, int to_type, struct
 
 void broadcast_announce_request(struct subnet_record *subrec, struct work_record *work)
 {
-       pstring outbuf;
+       char outbuf[1024];
        char *p;
 
        work->needannounce = True;
@@ -75,10 +76,10 @@ to subnet %s\n", work->work_group, subrec->subnet_name));
 
        SCVAL(p,0,work->token); /* (local) Unique workgroup token id. */
        p++;
-       p +=  push_string(NULL, p+1, global_myname(), 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
+       p +=  push_string_check(p+1, lp_netbios_name(), 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
   
        send_mailslot(False, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
-               global_myname(), 0x0, work->work_group,0x1e, subrec->bcast_ip, 
+               lp_netbios_name(), 0x0, work->work_group,0x1e, subrec->bcast_ip,
                subrec->myip, DGRAM_PORT);
 }
 
@@ -91,7 +92,7 @@ static void send_announcement(struct subnet_record *subrec, int announce_type,
                               time_t announce_interval,
                               const char *server_name, int server_type, const char *server_comment)
 {
-       pstring outbuf;
+       char outbuf[1024];
        unstring upper_server_name;
        char *p;
 
@@ -104,19 +105,22 @@ static void send_announcement(struct subnet_record *subrec, int announce_type,
        SCVAL(p,0,updatecount);
        SIVAL(p,1,announce_interval*1000); /* Milliseconds - despite the spec. */
 
-       safe_strcpy(upper_server_name, server_name, sizeof(upper_server_name)-1);
-       strupper_m(upper_server_name);
-       push_string(NULL, p+5, upper_server_name, 16, STR_ASCII|STR_TERMINATE);
+       strlcpy(upper_server_name, server_name ? server_name : "", sizeof(upper_server_name));
+       if (!strupper_m(upper_server_name)) {
+               DEBUG(2,("strupper_m %s failed\n", upper_server_name));
+               return;
+       }
+       push_string_check(p+5, upper_server_name, 16, STR_ASCII|STR_TERMINATE);
 
-       SCVAL(p,21,lp_major_announce_version()); /* Major version. */
-       SCVAL(p,22,lp_minor_announce_version()); /* Minor version. */
+       SCVAL(p,21,SAMBA_MAJOR_NBT_ANNOUNCE_VERSION); /* Major version. */
+       SCVAL(p,22,SAMBA_MINOR_NBT_ANNOUNCE_VERSION); /* Minor version. */
 
        SIVAL(p,23,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
        /* Browse version: got from NT/AS 4.00  - Value defined in smb.h (JHT). */
        SSVAL(p,27,BROWSER_ELECTION_VERSION);
        SSVAL(p,29,BROWSER_CONSTANT); /* Browse signature. */
 
-       p += 31 + push_string(NULL, p+31, server_comment, -1, STR_ASCII|STR_TERMINATE);
+       p += 31 + push_string_check(p+31, server_comment, sizeof(outbuf) - (p + 31 - outbuf), STR_ASCII|STR_TERMINATE);
 
        send_mailslot(False,BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
                        from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
@@ -132,20 +136,20 @@ static void send_lm_announcement(struct subnet_record *subrec, int announce_type
                               time_t announce_interval,
                               char *server_name, int server_type, char *server_comment)
 {
-       pstring outbuf;
+       char outbuf[1024];
        char *p=outbuf;
 
        memset(outbuf,'\0',sizeof(outbuf));
 
        SSVAL(p,0,announce_type);
        SIVAL(p,2,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
-       SCVAL(p,6,lp_major_announce_version()); /* Major version. */
-       SCVAL(p,7,lp_minor_announce_version()); /* Minor version. */
+       SCVAL(p,6,SAMBA_MAJOR_NBT_ANNOUNCE_VERSION); /* Major version. */
+       SCVAL(p,7,SAMBA_MINOR_NBT_ANNOUNCE_VERSION); /* Minor version. */
        SSVAL(p,8,announce_interval);            /* In seconds - according to spec. */
 
        p += 10;
-       p += push_string(NULL, p, server_name, 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
-       p += push_string(NULL, p, server_comment, sizeof(pstring)-15, STR_ASCII|STR_UPPER|STR_TERMINATE);
+       p += push_string_check(p, server_name, 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
+       p += push_string_check(p, server_comment, sizeof(outbuf)- (p - outbuf), STR_ASCII|STR_UPPER|STR_TERMINATE);
 
        send_mailslot(False,LANMAN_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
                from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
@@ -160,17 +164,17 @@ static void send_local_master_announcement(struct subnet_record *subrec, struct
                                            struct server_record *servrec)
 {
        /* Ensure we don't have the prohibited bit set. */
-       uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
+       uint32_t type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
 
        DEBUG(3,("send_local_master_announcement: type %x for name %s on subnet %s for workgroup %s\n",
-               type, global_myname(), subrec->subnet_name, work->work_group));
+               type, lp_netbios_name(), subrec->subnet_name, work->work_group));
 
        send_announcement(subrec, ANN_LocalMasterAnnouncement,
-                       global_myname(),                 /* From nbt name. */
+                       lp_netbios_name(),                 /* From nbt name. */
                        work->work_group, 0x1e,          /* To nbt name. */
                        subrec->bcast_ip,                /* To ip. */
                        work->announce_interval,         /* Time until next announce. */
-                       global_myname(),                 /* Name to announce. */
+                       lp_netbios_name(),                 /* Name to announce. */
                        type,                            /* Type field. */
                        servrec->serv.comment);
 }
@@ -185,13 +189,13 @@ static void send_workgroup_announcement(struct subnet_record *subrec, struct wor
                subrec->subnet_name, work->work_group));
 
        send_announcement(subrec, ANN_DomainAnnouncement,
-                       global_myname(),                 /* From nbt name. */
+                       lp_netbios_name(),                 /* From nbt name. */
                        MSBROWSE, 0x1,                   /* To nbt name. */
                        subrec->bcast_ip,                /* To ip. */
                        work->announce_interval,         /* Time until next announce. */
                        work->work_group,                /* Name to announce. */
                        SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT,  /* workgroup announce flags. */
-                       global_myname());                /* From name as comment. */
+                       lp_netbios_name());                /* From name as comment. */
 }
 
 /****************************************************************************
@@ -202,7 +206,7 @@ static void send_host_announcement(struct subnet_record *subrec, struct work_rec
                                    struct server_record *servrec)
 {
        /* Ensure we don't have the prohibited bits set. */
-       uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
+       uint32_t type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
 
        DEBUG(3,("send_host_announcement: type %x for host %s on subnet %s for workgroup %s\n",
                type, servrec->serv.name, subrec->subnet_name, work->work_group));
@@ -225,7 +229,7 @@ static void send_lm_host_announcement(struct subnet_record *subrec, struct work_
                                    struct server_record *servrec, int lm_interval)
 {
        /* Ensure we don't have the prohibited bits set. */
-       uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
+       uint32_t type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
 
        DEBUG(3,("send_lm_host_announcement: type %x for host %s on subnet %s for workgroup %s, ttl: %d\n",
                type, servrec->serv.name, subrec->subnet_name, work->work_group, lm_interval));
@@ -250,7 +254,7 @@ static void announce_server(struct subnet_record *subrec, struct work_record *wo
        /* Only do domain announcements if we are a master and it's
                our primary name we're being asked to announce. */
 
-       if (AM_LOCAL_MASTER_BROWSER(work) && strequal(global_myname(),servrec->serv.name)) {
+       if (AM_LOCAL_MASTER_BROWSER(work) && strequal(lp_netbios_name(),servrec->serv.name)) {
                send_local_master_announcement(subrec, work, servrec);
                send_workgroup_announcement(subrec, work);
        } else {
@@ -284,8 +288,10 @@ void announce_my_server_names(time_t t)
                        }
 
                        /* Announce every minute at first then progress to every 12 mins */
-                       if ((t - work->lastannounce_time) < work->announce_interval)
+                       if (t >= work->lastannounce_time &&
+                           (t - work->lastannounce_time) < work->announce_interval) {
                                continue;
+                       }
 
                        if (work->announce_interval < (CHECK_TIME_MAX_HOST_ANNCE * 60))
                                work->announce_interval += 60;
@@ -458,24 +464,27 @@ void announce_remote(time_t t)
        char *s;
        const char *ptr;
        static time_t last_time = 0;
-       pstring s2;
+       char *s2;
        struct in_addr addr;
        char *comment;
        int stype = lp_default_server_announce();
+       TALLOC_CTX *frame = NULL;
 
        if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
                return;
 
        last_time = t;
 
-       s = lp_remote_announce();
+       s = lp_remote_announce(talloc_tos());
        if (!*s)
                return;
 
-       comment = string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH);
+       comment = string_truncate(lp_server_string(talloc_tos()),
+                                 MAX_SERVER_STRING_LENGTH);
 
-       for (ptr=s; next_token(&ptr,s2,NULL,sizeof(s2)); ) {
-               /* The entries are of the form a.b.c.d/WORKGROUP with 
+       frame = talloc_stackframe();
+       for (ptr=s; next_token_talloc(frame,&ptr,&s2,NULL); ) {
+               /* The entries are of the form a.b.c.d/WORKGROUP with
                                WORKGROUP being optional */
                const char *wgroup;
                char *pwgroup;
@@ -489,8 +498,8 @@ void announce_remote(time_t t)
                else
                        wgroup = pwgroup;
 
-               addr = *interpret_addr2(s2);
-    
+               addr = interpret_addr2(s2);
+
                /* Announce all our names including aliases */
                /* Give the ip address as the address of our first
                                broadcast subnet. */
@@ -511,6 +520,7 @@ void announce_remote(time_t t)
                                                comment);
                }
        }
+       TALLOC_FREE(frame);
 }
 
 /****************************************************************************
@@ -519,23 +529,24 @@ void announce_remote(time_t t)
 **************************************************************************/
 
 void browse_sync_remote(time_t t)
-{  
+{
        char *s;
        const char *ptr;
-       static time_t last_time = 0; 
-       pstring s2;
+       static time_t last_time = 0;
+       char *s2;
        struct in_addr addr;
        struct work_record *work;
-       pstring outbuf;
+       char outbuf[1024];
        char *p;
        unstring myname;
+       TALLOC_CTX *frame = NULL;
+
        if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
                return;
-   
+
        last_time = t;
 
-       s = lp_remote_browse_sync();
+       s = lp_remote_browse_sync(talloc_tos());
        if (!*s)
                return;
 
@@ -549,33 +560,38 @@ void browse_sync_remote(time_t t)
                        lp_workgroup(), FIRST_SUBNET->subnet_name ));
                return;
        }
-         
+
        if(!AM_LOCAL_MASTER_BROWSER(work)) {
                DEBUG(5,("browse_sync_remote: We can only do this if we are a local master browser \
 for workgroup %s on subnet %s.\n", lp_workgroup(), FIRST_SUBNET->subnet_name ));
                return;
-       } 
+       }
 
        memset(outbuf,'\0',sizeof(outbuf));
        p = outbuf;
        SCVAL(p,0,ANN_MasterAnnouncement);
        p++;
 
-       unstrcpy(myname, global_myname());
-       strupper_m(myname);
+       unstrcpy(myname, lp_netbios_name());
+       if (!strupper_m(myname)) {
+               DEBUG(2,("strupper_m %s failed\n", myname));
+               return;
+       }
        myname[15]='\0';
-       push_pstring_base(p, myname, outbuf);
+       push_ascii(p, myname, sizeof(outbuf)-PTR_DIFF(p,outbuf)-1, STR_TERMINATE);
 
-       p = skip_string(p,1);
+       p = skip_string(outbuf,sizeof(outbuf),p);
 
-       for (ptr=s; next_token(&ptr,s2,NULL,sizeof(s2)); ) {
+       frame = talloc_stackframe();
+       for (ptr=s; next_token_talloc(frame,&ptr,&s2,NULL); ) {
                /* The entries are of the form a.b.c.d */
-               addr = *interpret_addr2(s2);
+               addr = interpret_addr2(s2);
 
                DEBUG(5,("announce_remote: Doing remote browse sync announce for server %s to IP %s.\n",
-                       global_myname(), inet_ntoa(addr) ));
+                       lp_netbios_name(), inet_ntoa(addr) ));
 
                send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
-                       global_myname(), 0x0, "*", 0x0, addr, FIRST_SUBNET->myip, DGRAM_PORT);
+                       lp_netbios_name(), 0x0, "*", 0x0, addr, FIRST_SUBNET->myip, DGRAM_PORT);
        }
+       TALLOC_FREE(frame);
 }