Merge branch 'work/v3-2-test' into v3-2-test
[ira/wip.git] / source3 / nmbd / nmbd_packets.c
index b5cbaab00b7850eae547cddeeddcf4832d893492..c1d373aa189038af44a036c8eb70b70381138ba4 100644 (file)
@@ -7,7 +7,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,
@@ -16,8 +16,7 @@
    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/>.
    
 */
 
@@ -29,11 +28,9 @@ extern int global_nmb_port;
 
 extern int num_response_packets;
 
-extern struct in_addr loopback_ip;
-
 static void queue_packet(struct packet_struct *packet);
 
-BOOL rescan_listen_set = False;
+bool rescan_listen_set = False;
 
 
 /*******************************************************************
@@ -53,7 +50,7 @@ static int find_subnet_fd_for_address( struct in_addr local_ip )
        struct subnet_record *subrec;
 
        for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
-               if(ip_equal(local_ip, subrec->myip))
+               if(ip_equal_v4(local_ip, subrec->myip))
                        return subrec->nmb_sock;
 
        return ClientNMB;
@@ -68,7 +65,7 @@ static int find_subnet_mailslot_fd_for_address( struct in_addr local_ip )
        struct subnet_record *subrec;
 
        for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
-               if(ip_equal(local_ip, subrec->myip))
+               if(ip_equal_v4(local_ip, subrec->myip))
                        return subrec->dgram_sock;
 
        return ClientDGRAM;
@@ -144,12 +141,12 @@ static uint16 generate_name_trn_id(void)
  Either loops back or sends out a completed NetBIOS packet.
 **************************************************************************/
 
-static BOOL send_netbios_packet(struct packet_struct *p)
+static bool send_netbios_packet(struct packet_struct *p)
 {
-       BOOL loopback_this_packet = False;
+       bool loopback_this_packet = False;
 
        /* Check if we are sending to or from ourselves as a WINS server. */
-       if(ismyip(p->ip) && (p->port == global_nmb_port))
+       if(ismyip_v4(p->ip) && (p->port == global_nmb_port))
                loopback_this_packet = True;
 
        if(loopback_this_packet) {
@@ -177,14 +174,14 @@ static BOOL send_netbios_packet(struct packet_struct *p)
 **************************************************************************/
 
 static struct packet_struct *create_and_init_netbios_packet(struct nmb_name *nmbname,
-                                                            BOOL bcast, BOOL rec_des,
+                                                            bool bcast, bool rec_des,
                                                             struct in_addr to_ip)
 {
        struct packet_struct *packet = NULL;
        struct nmb_packet *nmb = NULL;
 
        /* Allocate the packet_struct we will return. */
-       if((packet = (struct packet_struct *)malloc(sizeof(*packet))) == NULL) {
+       if((packet = SMB_MALLOC_P(struct packet_struct)) == NULL) {
                DEBUG(0,("create_and_init_netbios_packet: malloc fail (1) for packet struct.\n"));
                return NULL;
        }
@@ -224,14 +221,14 @@ static struct packet_struct *create_and_init_netbios_packet(struct nmb_name *nmb
  Sets up the common elements of register, refresh or release packet.
 **************************************************************************/
 
-static BOOL create_and_init_additional_record(struct packet_struct *packet,
+static bool create_and_init_additional_record(struct packet_struct *packet,
                                                      uint16 nb_flags,
-                                                     struct in_addr *register_ip)
+                                                     const struct in_addr *register_ip)
 {
        struct nmb_packet *nmb = &packet->packet.nmb;
 
-       if((nmb->additional = (struct res_rec *)malloc(sizeof(struct res_rec))) == NULL) {
-               DEBUG(0,("initiate_name_register_packet: malloc fail for additional record.\n"));
+       if((nmb->additional = SMB_MALLOC_P(struct res_rec)) == NULL) {
+               DEBUG(0,("create_and_init_additional_record: malloc fail for additional record.\n"));
                return False;
        }
 
@@ -272,7 +269,7 @@ static BOOL create_and_init_additional_record(struct packet_struct *packet,
  Sends out a name query.
 **************************************************************************/
 
-static BOOL initiate_name_query_packet( struct packet_struct *packet)
+static bool initiate_name_query_packet( struct packet_struct *packet)
 {
        struct nmb_packet *nmb = NULL;
 
@@ -294,7 +291,7 @@ static BOOL initiate_name_query_packet( struct packet_struct *packet)
  Sends out a name query - from a WINS server. 
 **************************************************************************/
 
-static BOOL initiate_name_query_packet_from_wins_server( struct packet_struct *packet)
+static bool initiate_name_query_packet_from_wins_server( struct packet_struct *packet)
 {   
        struct nmb_packet *nmb = NULL;
   
@@ -316,8 +313,8 @@ static BOOL initiate_name_query_packet_from_wins_server( struct packet_struct *p
  Sends out a name register.
 **************************************************************************/
 
-static BOOL initiate_name_register_packet( struct packet_struct *packet,
-                                    uint16 nb_flags, struct in_addr *register_ip)
+static bool initiate_name_register_packet( struct packet_struct *packet,
+                                    uint16 nb_flags, const struct in_addr *register_ip)
 {
        struct nmb_packet *nmb = &packet->packet.nmb;
 
@@ -340,7 +337,7 @@ static BOOL initiate_name_register_packet( struct packet_struct *packet,
  Sends out a multihomed name register.
 **************************************************************************/
 
-static BOOL initiate_multihomed_name_register_packet(struct packet_struct *packet,
+static bool initiate_multihomed_name_register_packet(struct packet_struct *packet,
                                                     uint16 nb_flags, struct in_addr *register_ip)
 {
        struct nmb_packet *nmb = &packet->packet.nmb;
@@ -368,7 +365,7 @@ for name %s IP %s (bcast=%s) to IP %s\n",
  Sends out a name refresh.
 **************************************************************************/
 
-static BOOL initiate_name_refresh_packet( struct packet_struct *packet,
+static bool initiate_name_refresh_packet( struct packet_struct *packet,
                                    uint16 nb_flags, struct in_addr *refresh_ip)
 {
        struct nmb_packet *nmb = &packet->packet.nmb;
@@ -392,7 +389,7 @@ static BOOL initiate_name_refresh_packet( struct packet_struct *packet,
  Sends out a name release.
 **************************************************************************/
 
-static BOOL initiate_name_release_packet( struct packet_struct *packet,
+static bool initiate_name_release_packet( struct packet_struct *packet,
                                    uint16 nb_flags, struct in_addr *release_ip)
 {
        struct nmb_packet *nmb = &packet->packet.nmb;
@@ -416,7 +413,7 @@ static BOOL initiate_name_release_packet( struct packet_struct *packet,
  Sends out a node status.
 **************************************************************************/
 
-static BOOL initiate_node_status_packet( struct packet_struct *packet )
+static bool initiate_node_status_packet( struct packet_struct *packet )
 {
        struct nmb_packet *nmb = &packet->packet.nmb;
 
@@ -445,7 +442,7 @@ static BOOL initiate_node_status_packet( struct packet_struct *packet )
  broadcast subnet.
 ****************************************************************************/
 
-static BOOL assert_check_subnet(struct subnet_record *subrec)
+static bool assert_check_subnet(struct subnet_record *subrec)
 {
        if( subrec == remote_broadcast_subnet) {
                DEBUG(0,("assert_check_subnet: Attempt to send packet on remote broadcast subnet. \
@@ -470,7 +467,8 @@ struct response_record *queue_register_name( struct subnet_record *subrec,
 {
        struct packet_struct *p;
        struct response_record *rrec;
-
+       struct sockaddr_storage ss;
+       const struct sockaddr_storage *pss = NULL;
        if(assert_check_subnet(subrec))
                return NULL;
 
@@ -479,7 +477,16 @@ struct response_record *queue_register_name( struct subnet_record *subrec,
                                subrec->bcast_ip)) == NULL)
                return NULL;
 
-       if(initiate_name_register_packet( p, nb_flags, iface_ip(subrec->bcast_ip)) == False) {
+       in_addr_to_sockaddr_storage(&ss, subrec->bcast_ip);
+       pss = iface_ip(&ss);
+       if (!pss || pss->ss_family != AF_INET) {
+               p->locked = False;
+               free_packet(p);
+               return NULL;
+       }
+
+       if(initiate_name_register_packet(p, nb_flags,
+                       &((const struct sockaddr_in *)pss)->sin_addr) == False) {
                p->locked = False;
                free_packet(p);
                return NULL;
@@ -534,8 +541,10 @@ void queue_wins_refresh(struct nmb_name *nmbname,
        DEBUG(6,("Refreshing name %s IP %s with WINS server %s using tag '%s'\n",
                 nmb_namestr(nmbname), ip_str, inet_ntoa(wins_ip), tag));
 
-       userdata = (struct userdata_struct *)malloc(sizeof(*userdata) + strlen(tag) + 1);
+       userdata = (struct userdata_struct *)SMB_MALLOC(sizeof(*userdata) + strlen(tag) + 1);
        if (!userdata) {
+               p->locked = False;
+               free_packet(p);
                DEBUG(0,("Failed to allocate userdata structure!\n"));
                return;
        }
@@ -578,7 +587,7 @@ struct response_record *queue_register_multihomed_name( struct subnet_record *su
 {
        struct packet_struct *p;
        struct response_record *rrec;
-       BOOL ret;
+       bool ret;
        
        /* Sanity check. */
        if(subrec != unicast_subnet) {
@@ -697,7 +706,7 @@ struct response_record *queue_query_name( struct subnet_record *subrec,
   
        /* queries to the WINS server turn up here as queries to IP 0.0.0.0 
                        These need to be handled a bit differently */
-       if (subrec->type == UNICAST_SUBNET && is_zero_ip(to_ip)) {
+       if (subrec->type == UNICAST_SUBNET && is_zero_ip_v4(to_ip)) {
                /* What we really need to do is loop over each of our wins
                 * servers and wins server tags here, but that just doesn't
                 * fit our architecture at the moment (userdata may already
@@ -723,14 +732,14 @@ struct response_record *queue_query_name( struct subnet_record *subrec,
 
                DEBUG(10,("queue_query_name: bind_interfaces_only is set, looking for suitable source IP\n"));
                for(i = 0; i < iface_count(); i++) {
-                       struct in_addr *ifip = iface_n_ip(i);
+                       const struct in_addr *ifip = iface_n_ip_v4(i);
 
-                       if(ifip == NULL) {
+                       if (ifip == NULL) {
                                DEBUG(0,("queue_query_name: interface %d has NULL IP address !\n", i));
                                continue;
                        }
 
-                       if (ip_equal(*ifip,loopback_ip)) {
+                       if (is_loopback_ip_v4(*ifip)) {
                                DEBUG(5,("queue_query_name: ignoring loopback interface (%d)\n", i));
                                continue;
                        }
@@ -765,7 +774,7 @@ struct response_record *queue_query_name( struct subnet_record *subrec,
 /****************************************************************************
  Queue a query name packet to a given address from the WINS subnet.
 ****************************************************************************/
+
 struct response_record *queue_query_name_from_wins_server( struct in_addr to_ip,
                           response_function resp_fn,
                           timeout_response_function timeout_fn,
@@ -804,7 +813,7 @@ struct response_record *queue_query_name_from_wins_server( struct in_addr to_ip,
 /****************************************************************************
  Queue a node status packet to a given name and address.
 ****************************************************************************/
+
 struct response_record *queue_node_status( struct subnet_record *subrec,
                           response_function resp_fn,
                           timeout_response_function timeout_fn,
@@ -834,7 +843,7 @@ unicast subnet. subnet is %s\n.", subrec->subnet_name ));
                p->locked = False;
                free_packet(p);
                return NULL;
-       } 
+       }
 
        if((rrec = make_response_record(subrec,           /* subnet record. */
                                        p,                     /* packet we sent. */
@@ -863,13 +872,14 @@ void reply_netbios_packet(struct packet_struct *orig_packet,
        struct nmb_packet *nmb = NULL;
        struct res_rec answers;
        struct nmb_packet *orig_nmb = &orig_packet->packet.nmb;
-       BOOL loopback_this_packet = False;
+       bool loopback_this_packet = False;
+       int rr_type = RR_TYPE_NB;
        const char *packet_type = "unknown";
-  
+
        /* Check if we are sending to or from ourselves. */
-       if(ismyip(orig_packet->ip) && (orig_packet->port == global_nmb_port))
+       if(ismyip_v4(orig_packet->ip) && (orig_packet->port == global_nmb_port))
                loopback_this_packet = True;
-  
+
        nmb = &packet.packet.nmb;
 
        /* Do a partial copy of the packet. We clear the locked flag and
@@ -885,11 +895,15 @@ void reply_netbios_packet(struct packet_struct *orig_packet,
                        packet_type = "nmb_status";
                        nmb->header.nm_flags.recursion_desired = False;
                        nmb->header.nm_flags.recursion_available = False;
+                       rr_type = RR_TYPE_NBSTAT;
                        break;
                case NMB_QUERY:
                        packet_type = "nmb_query";
                        nmb->header.nm_flags.recursion_desired = True;
                        nmb->header.nm_flags.recursion_available = True;
+                       if (rcode) {
+                               rr_type = RR_TYPE_NULL;
+                       }
                        break;
                case NMB_REG:
                case NMB_REG_REFRESH:
@@ -906,6 +920,7 @@ void reply_netbios_packet(struct packet_struct *orig_packet,
                        packet_type = "nmb_wack";
                        nmb->header.nm_flags.recursion_desired = False;
                        nmb->header.nm_flags.recursion_available = False;
+                       rr_type = RR_TYPE_NULL;
                        break;
                case WINS_REG:
                        packet_type = "wins_reg";
@@ -916,6 +931,9 @@ void reply_netbios_packet(struct packet_struct *orig_packet,
                        packet_type = "wins_query";
                        nmb->header.nm_flags.recursion_desired = True;
                        nmb->header.nm_flags.recursion_available = True;
+                       if (rcode) {
+                               rr_type = RR_TYPE_NULL;
+                       }
                        break;
                default:
                        DEBUG(0,("reply_netbios_packet: Unknown packet type: %s %s to ip %s\n",
@@ -934,28 +952,34 @@ for id %hu\n", packet_type, nmb_namestr(&orig_nmb->question.question_name),
        nmb->header.nm_flags.bcast = False;
        nmb->header.nm_flags.trunc = False;
        nmb->header.nm_flags.authoritative = True;
-  
+
        nmb->header.rcode = rcode;
        nmb->header.qdcount = 0;
        nmb->header.ancount = 1;
        nmb->header.nscount = 0;
        nmb->header.arcount = 0;
-  
+
        memset((char*)&nmb->question,'\0',sizeof(nmb->question));
-  
+
        nmb->answers = &answers;
        memset((char*)nmb->answers,'\0',sizeof(*nmb->answers));
-  
+
        nmb->answers->rr_name  = orig_nmb->question.question_name;
-       nmb->answers->rr_type  = orig_nmb->question.question_type;
-       nmb->answers->rr_class = orig_nmb->question.question_class;
+       nmb->answers->rr_type  = rr_type;
+       nmb->answers->rr_class = RR_CLASS_IN;
        nmb->answers->ttl      = ttl;
-  
+
        if (data && len) {
+               if (len < 0 || len > sizeof(nmb->answers->rdata)) {
+                       DEBUG(5,("reply_netbios_packet: "
+                               "invalid packet len (%d)\n",
+                               len ));
+                       return;
+               }
                nmb->answers->rdlength = len;
                memcpy(nmb->answers->rdata, data, len);
        }
-  
+
        packet.packet_type = NMB_PACKET;
        /* Ensure we send out on the same fd that the original
                packet came in on to give the correct source IP address. */
@@ -963,7 +987,7 @@ for id %hu\n", packet_type, nmb_namestr(&orig_nmb->question.question_name),
        packet.timestamp = time(NULL);
 
        debug_nmb_packet(&packet);
-  
+
        if(loopback_this_packet) {
                struct packet_struct *lo_packet;
                DEBUG(5,("reply_netbios_packet: sending packet to ourselves.\n"));
@@ -990,9 +1014,9 @@ static void queue_packet(struct packet_struct *packet)
                packet_queue = packet;
                return;
        }
-  
+
        /* find the bottom */
-       for (p=packet_queue;p->next;p=p->next) 
+       for (p=packet_queue;p->next;p=p->next)
                ;
 
        p->next = packet;
@@ -1010,7 +1034,7 @@ static struct subnet_record *find_subnet_for_dgram_browse_packet(struct packet_s
 
        /* Go through all the broadcast subnets and see if the mask matches. */
        for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
-               if(same_net(p->ip, subrec->bcast_ip, subrec->mask_ip))
+               if(same_net_v4(p->ip, subrec->bcast_ip, subrec->mask_ip))
                        return subrec;
        }
 
@@ -1034,7 +1058,7 @@ static void process_browse_packet(struct packet_struct *p, char *buf,int len)
        int command = CVAL(buf,0);
        struct subnet_record *subrec = find_subnet_for_dgram_browse_packet(p);
        char scope[64];
-       fstring src_name;
+       unstring src_name;
 
        /* Drop the packet if it's a different NetBIOS scope, or the source is from one of our names. */
        pull_ascii(scope, dgram->dest_name.scope, 64, 64, STR_TERMINATE);
@@ -1094,7 +1118,7 @@ packet from %s IP %s\n", nmb_namestr(&dgram->source_name), inet_ntoa(p->ip)));
                        process_master_browser_announce(subrec, p, buf+1);
                        break;
                case ANN_BecomeBackup:
-                       /* 
+                       /*
                         * We don't currently implement this. Log it just in case.
                         */
                        debug_browse_data(buf, len);
@@ -1108,7 +1132,7 @@ command ANN_BecomeBackup from %s IP %s to %s\n", subrec->subnet_name, nmb_namest
 command code %d from %s IP %s to %s\n", subrec->subnet_name, command, nmb_namestr(&dgram->source_name),
                                inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
                        break;
-       } 
+       }
 }
 
 /****************************************************************************
@@ -1121,7 +1145,7 @@ static void process_lanman_packet(struct packet_struct *p, char *buf,int len)
        int command = SVAL(buf,0);
        struct subnet_record *subrec = find_subnet_for_dgram_browse_packet(p);
        char scope[64];
-       fstring src_name;
+       unstring src_name;
 
        /* Drop the packet if it's a different NetBIOS scope, or the source is from one of our names. */
 
@@ -1142,10 +1166,10 @@ mismatch with our scope (%s).\n", inet_ntoa(p->ip), scope, global_scope()));
        switch (command) {
                case ANN_HostAnnouncement:
                        debug_browse_data(buf, len);
-                       process_lm_host_announce(subrec, p, buf+1);
+                       process_lm_host_announce(subrec, p, buf+1, len > 1 ? len-1 : 0);
                        break;
                case ANN_AnnouncementRequest:
-                       process_lm_announce_request(subrec, p, buf+1);
+                       process_lm_announce_request(subrec, p, buf+1, len > 1 ? len-1 : 0);
                        break;
                default:
                        DEBUG(0,("process_lanman_packet: On subnet %s ignoring browse packet \
@@ -1161,12 +1185,12 @@ command code %d from %s IP %s to %s\n", subrec->subnet_name, command, nmb_namest
   stage as subsequent processing is expensive. 
 ****************************************************************************/
 
-static BOOL listening(struct packet_struct *p,struct nmb_name *nbname)
+static bool listening(struct packet_struct *p,struct nmb_name *nbname)
 {
        struct subnet_record *subrec = NULL;
 
        for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
-               if(same_net(p->ip, subrec->bcast_ip, subrec->mask_ip))
+               if(same_net_v4(p->ip, subrec->bcast_ip, subrec->mask_ip))
                        break;
        }
 
@@ -1203,6 +1227,16 @@ an error packet of type %x\n", nmb_namestr(&dgram->dest_name), inet_ntoa(p->ip),
                return;
        }
 
+       /* Ensure we have a large enough packet before looking inside. */
+       if (dgram->datasize < (smb_vwv12 - 2)) {
+               /* That's the offset minus the 4 byte length + 2 bytes of offset. */
+               DEBUG(0,("process_dgram: ignoring too short dgram packet (%u) sent to name %s from IP %s\n",
+                       (unsigned int)dgram->datasize,
+                       nmb_namestr(&dgram->dest_name),
+                       inet_ntoa(p->ip) ));
+               return;
+       }
+
        buf = &dgram->data[0];
        buf -= 4; /* XXXX for the pseudo tcp length - someday I need to get rid of this */
 
@@ -1212,14 +1246,36 @@ an error packet of type %x\n", nmb_namestr(&dgram->dest_name), inet_ntoa(p->ip),
        len = SVAL(buf,smb_vwv11);
        buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
 
-       if (len <= 0)
+       if (len <= 0 || len > dgram->datasize) {
+               DEBUG(0,("process_dgram: ignoring malformed1 (datasize = %d, len = %d) datagram \
+packet sent to name %s from IP %s\n",
+                       dgram->datasize,
+                       len,
+                       nmb_namestr(&dgram->dest_name),
+                       inet_ntoa(p->ip) ));
+               return;
+       }
+
+       if (buf2 < dgram->data || (buf2 >= dgram->data + dgram->datasize)) {
+               DEBUG(0,("process_dgram: ignoring malformed2 (datasize = %d, len=%d, off=%d) datagram \
+packet sent to name %s from IP %s\n",
+                       dgram->datasize,
+                       len,
+                       (int)PTR_DIFF(buf2, dgram->data),
+                       nmb_namestr(&dgram->dest_name),
+                       inet_ntoa(p->ip) ));
                return;
+       }
 
-       if (buf2 + len > buf + sizeof(dgram->data)) {
-               DEBUG(2,("process_dgram: datagram from %s to %s IP %s for %s len=%d too long.\n",
-                       nmb_namestr(&dgram->source_name),nmb_namestr(&dgram->dest_name),
-                       inet_ntoa(p->ip), smb_buf(buf),len));
-               len = (buf + sizeof(dgram->data)) - buf;
+       if ((buf2 + len < dgram->data) || (buf2 + len > dgram->data + dgram->datasize)) {
+               DEBUG(0,("process_dgram: ignoring malformed3 (datasize = %d, len=%d, off=%d) datagram \
+packet sent to name %s from IP %s\n",
+                       dgram->datasize,
+                       len,
+                       (int)PTR_DIFF(buf2, dgram->data),
+                       nmb_namestr(&dgram->dest_name),
+                       inet_ntoa(p->ip) ));
+               return;
        }
 
        DEBUG(4,("process_dgram: datagram from %s to %s IP %s for %s of type %d len=%d\n",
@@ -1257,9 +1313,9 @@ an error packet of type %x\n", nmb_namestr(&dgram->dest_name), inet_ntoa(p->ip),
   Validate a response nmb packet.
 ****************************************************************************/
 
-static BOOL validate_nmb_response_packet( struct nmb_packet *nmb )
+static bool validate_nmb_response_packet( struct nmb_packet *nmb )
 {
-       BOOL ignore = False;
+       bool ignore = False;
 
        switch (nmb->header.opcode) {
                case NMB_NAME_REG_OPCODE:
@@ -1303,14 +1359,14 @@ static BOOL validate_nmb_response_packet( struct nmb_packet *nmb )
 
        return ignore;
 }
+
 /****************************************************************************
   Validate a request nmb packet.
 ****************************************************************************/
 
-static BOOL validate_nmb_packet( struct nmb_packet *nmb )
+static bool validate_nmb_packet( struct nmb_packet *nmb )
 {
-       BOOL ignore = False;
+       bool ignore = False;
 
        switch (nmb->header.opcode) {
                case NMB_NAME_REG_OPCODE:
@@ -1397,7 +1453,7 @@ static struct subnet_record *find_subnet_for_nmb_packet( struct packet_struct *p
 
        /* Go through all the broadcast subnets and see if the mask matches. */
        for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
-               if(same_net(p->ip, subrec->bcast_ip, subrec->mask_ip))
+               if(same_net_v4(p->ip, subrec->bcast_ip, subrec->mask_ip))
                        return subrec;
        }
 
@@ -1468,7 +1524,7 @@ not allowed.\n"));
                                        break;
                        }
                        break;
-      
+
                case NMB_NAME_RELEASE_OPCODE:
                        if(subrec == wins_server_subnet)
                                wins_process_name_release_request(subrec, p);
@@ -1507,7 +1563,7 @@ found for id = %hu. Ignoring packet.\n", nmb->header.name_trn_id));
        rrec->num_msgs++;
        /* Ensure we don't re-send the request. */
        rrec->repeat_count = 0;
-  
+
        /* Call the response received function for this packet. */
        (*rrec->resp_fn)(subrec, rrec, p);
 }
@@ -1540,7 +1596,7 @@ void run_packet_queue(void)
                }
                free_packet(p);
        }
-} 
+}
 
 /*******************************************************************
  Retransmit or timeout elements from all the outgoing subnet response
@@ -1557,9 +1613,11 @@ void retransmit_or_expire_response_records(time_t t)
        for (subrec = FIRST_SUBNET; subrec; subrec = get_next_subnet_maybe_unicast_or_wins_server(subrec)) {
                struct response_record *rrec, *nextrrec;
 
+  restart:
+
                for (rrec = subrec->responselist; rrec; rrec = nextrrec) {
                        nextrrec = rrec->next;
-   
+
                        if (rrec->repeat_time <= t) {
                                if (rrec->repeat_count > 0) {
                                        /* Resend while we have a non-zero repeat_count. */
@@ -1595,6 +1653,9 @@ on subnet %s\n", rrec->response_id, inet_ntoa(rrec->packet->ip), subrec->subnet_
                                                                        no timeout function. */
                                                        remove_response_record(subrec, rrec);
                                                }
+                                               /* We have changed subrec->responselist,
+                                                * restart from the beginning of this list. */
+                                               goto restart;
                                        } /* !rrec->in_expitation_processing */
                                } /* rrec->repeat_count > 0 */
                        } /* rrec->repeat_time <= t */
@@ -1607,13 +1668,13 @@ on subnet %s\n", rrec->response_id, inet_ntoa(rrec->packet->ip), subrec->subnet_
   plus the broadcast sockets.
 ***************************************************************************/
 
-static BOOL create_listen_fdset(fd_set **ppset, int **psock_array, int *listen_number)
+static bool create_listen_fdset(fd_set **ppset, int **psock_array, int *listen_number, int *maxfd)
 {
        int *sock_array = NULL;
        struct subnet_record *subrec = NULL;
        int count = 0;
        int num = 0;
-       fd_set *pset = (fd_set *)malloc(sizeof(fd_set));
+       fd_set *pset = SMB_MALLOC_P(fd_set);
 
        if(pset == NULL) {
                DEBUG(0,("create_listen_fdset: malloc fail !\n"));
@@ -1627,11 +1688,13 @@ static BOOL create_listen_fdset(fd_set **ppset, int **psock_array, int *listen_n
        if((count*2) + 2 > FD_SETSIZE) {
                DEBUG(0,("create_listen_fdset: Too many file descriptors needed (%d). We can \
 only use %d.\n", (count*2) + 2, FD_SETSIZE));
+               SAFE_FREE(pset);
                return True;
        }
 
-       if((sock_array = (int *)malloc(((count*2) + 2)*sizeof(int))) == NULL) {
+       if((sock_array = SMB_MALLOC_ARRAY(int, (count*2) + 2)) == NULL) {
                DEBUG(0,("create_listen_fdset: malloc fail for socket array.\n"));
+               SAFE_FREE(pset);
                return True;
        }
 
@@ -1640,21 +1703,25 @@ only use %d.\n", (count*2) + 2, FD_SETSIZE));
        /* Add in the broadcast socket on 137. */
        FD_SET(ClientNMB,pset);
        sock_array[num++] = ClientNMB;
+       *maxfd = MAX( *maxfd, ClientNMB);
 
        /* Add in the 137 sockets on all the interfaces. */
        for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
                FD_SET(subrec->nmb_sock,pset);
                sock_array[num++] = subrec->nmb_sock;
+               *maxfd = MAX( *maxfd, subrec->nmb_sock);
        }
 
        /* Add in the broadcast socket on 138. */
        FD_SET(ClientDGRAM,pset);
        sock_array[num++] = ClientDGRAM;
+       *maxfd = MAX( *maxfd, ClientDGRAM);
 
        /* Add in the 138 sockets on all the interfaces. */
        for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
                FD_SET(subrec->dgram_sock,pset);
                sock_array[num++] = subrec->dgram_sock;
+               *maxfd = MAX( *maxfd, subrec->dgram_sock);
        }
 
        *listen_number = (count*2) + 2;
@@ -1664,7 +1731,7 @@ only use %d.\n", (count*2) + 2, FD_SETSIZE));
 
        *ppset = pset;
        *psock_array = sock_array;
+
        return False;
 }
 
@@ -1673,14 +1740,16 @@ only use %d.\n", (count*2) + 2, FD_SETSIZE));
   return True if the socket is dead
 ***************************************************************************/
 
-BOOL listen_for_packets(BOOL run_election)
+bool listen_for_packets(bool run_election)
 {
        static fd_set *listen_set = NULL;
        static int listen_number = 0;
        static int *sock_array = NULL;
        int i;
+       static int maxfd = 0;
 
-       fd_set fds;
+       fd_set r_fds;
+       fd_set w_fds;
        int selrtn;
        struct timeval timeout;
 #ifndef SYNC_DNS
@@ -1688,23 +1757,25 @@ BOOL listen_for_packets(BOOL run_election)
 #endif
 
        if(listen_set == NULL || rescan_listen_set) {
-               if(create_listen_fdset(&listen_set, &sock_array, &listen_number)) {
+               if(create_listen_fdset(&listen_set, &sock_array, &listen_number, &maxfd)) {
                        DEBUG(0,("listen_for_packets: Fatal error. unable to create listen set. Exiting.\n"));
                        return True;
                }
                rescan_listen_set = False;
        }
 
-       memcpy((char *)&fds, (char *)listen_set, sizeof(fd_set));
+       memcpy((char *)&r_fds, (char *)listen_set, sizeof(fd_set));
+       FD_ZERO(&w_fds);
 
 #ifndef SYNC_DNS
        dns_fd = asyncdns_fd();
        if (dns_fd != -1) {
-               FD_SET(dns_fd, &fds);
+               FD_SET(dns_fd, &r_fds);
+               maxfd = MAX( maxfd, dns_fd);
        }
 #endif
 
-       /* 
+       /*
         * During elections and when expecting a netbios response packet we
         * need to send election packets at tighter intervals.
         * Ideally it needs to be the interval (in ms) between time now and
@@ -1714,11 +1785,24 @@ BOOL listen_for_packets(BOOL run_election)
        timeout.tv_sec = (run_election||num_response_packets) ? 1 : NMBD_SELECT_LOOP;
        timeout.tv_usec = 0;
 
+       {
+               struct timeval now = timeval_current();
+               event_add_to_select_args(nmbd_event_context(), &now,
+                                        &r_fds, &w_fds, &timeout, &maxfd);
+       }
+
+       if (timeval_is_zero(&timeout)) {
+               /* Process a timed event now... */
+               if (run_events(nmbd_event_context(), 0, NULL, NULL)) {
+                       return False;
+               }
+       }
+
        /* Prepare for the select - allow certain signals. */
 
        BlockSignals(False, SIGTERM);
 
-       selrtn = sys_select(FD_SETSIZE,&fds,NULL,NULL,&timeout);
+       selrtn = sys_select(maxfd+1,&r_fds,&w_fds,NULL,&timeout);
 
        /* We can only take signals when we are in the select - block them again here. */
 
@@ -1728,8 +1812,12 @@ BOOL listen_for_packets(BOOL run_election)
                return False;
        }
 
+       if (run_events(nmbd_event_context(), selrtn, &r_fds, &w_fds)) {
+               return False;
+       }
+
 #ifndef SYNC_DNS
-       if (dns_fd != -1 && FD_ISSET(dns_fd,&fds)) {
+       if (dns_fd != -1 && FD_ISSET(dns_fd,&r_fds)) {
                run_dns_queue();
        }
 #endif
@@ -1737,7 +1825,7 @@ BOOL listen_for_packets(BOOL run_election)
        for(i = 0; i < listen_number; i++) {
                if (i < (listen_number/2)) {
                        /* Processing a 137 socket. */
-                       if (FD_ISSET(sock_array[i],&fds)) {
+                       if (FD_ISSET(sock_array[i],&r_fds)) {
                                struct packet_struct *packet = read_packet(sock_array[i], NMB_PACKET);
                                if (packet) {
                                        /*
@@ -1745,12 +1833,12 @@ BOOL listen_for_packets(BOOL run_election)
                                         * only is set then check it came from one of our local nets. 
                                         */
                                        if(lp_bind_interfaces_only() && (sock_array[i] == ClientNMB) && 
-                                                               (!is_local_net(packet->ip))) {
+                                                               (!is_local_net_v4(packet->ip))) {
                                                DEBUG(7,("discarding nmb packet sent to broadcast socket from %s:%d\n",
                                                        inet_ntoa(packet->ip),packet->port));     
                                                free_packet(packet);
-                                       } else if ((ip_equal(loopback_ip, packet->ip) || 
-                                                               ismyip(packet->ip)) && packet->port == global_nmb_port &&
+                                       } else if ((is_loopback_ip_v4(packet->ip) || 
+                                                               ismyip_v4(packet->ip)) && packet->port == global_nmb_port &&
                                                                packet->packet.nmb.header.nm_flags.bcast) {
                                                DEBUG(7,("discarding own bcast packet from %s:%d\n",
                                                        inet_ntoa(packet->ip),packet->port));     
@@ -1764,7 +1852,7 @@ BOOL listen_for_packets(BOOL run_election)
                        }
                } else {
                        /* Processing a 138 socket. */
-                               if (FD_ISSET(sock_array[i],&fds)) {
+                               if (FD_ISSET(sock_array[i],&r_fds)) {
                                struct packet_struct *packet = read_packet(sock_array[i], DGRAM_PACKET);
                                if (packet) {
                                        /*
@@ -1772,12 +1860,12 @@ BOOL listen_for_packets(BOOL run_election)
                                         * only is set then check it came from one of our local nets. 
                                         */
                                        if(lp_bind_interfaces_only() && (sock_array[i] == ClientDGRAM) && 
-                                                               (!is_local_net(packet->ip))) {
+                                                               (!is_local_net_v4(packet->ip))) {
                                                DEBUG(7,("discarding dgram packet sent to broadcast socket from %s:%d\n",
                                                inet_ntoa(packet->ip),packet->port));     
                                                free_packet(packet);
-                                       } else if ((ip_equal(loopback_ip, packet->ip) || 
-                                                       ismyip(packet->ip)) && packet->port == DGRAM_PORT) {
+                                       } else if ((is_loopback_ip_v4(packet->ip) || 
+                                                       ismyip_v4(packet->ip)) && packet->port == DGRAM_PORT) {
                                                DEBUG(7,("discarding own dgram packet from %s:%d\n",
                                                        inet_ntoa(packet->ip),packet->port));     
                                                free_packet(packet);
@@ -1797,13 +1885,13 @@ BOOL listen_for_packets(BOOL run_election)
   Construct and send a netbios DGRAM.
 **************************************************************************/
 
-BOOL send_mailslot(BOOL unique, const char *mailslot,char *buf, size_t len,
+bool send_mailslot(bool unique, const char *mailslot,char *buf, size_t len,
                    const char *srcname, int src_type,
                    const char *dstname, int dest_type,
                    struct in_addr dest_ip,struct in_addr src_ip,
                   int dest_port)
 {
-       BOOL loopback_this_packet = False;
+       bool loopback_this_packet = False;
        struct packet_struct p;
        struct dgram_packet *dgram = &p.packet.dgram;
        char *ptr,*p2;
@@ -1811,13 +1899,13 @@ BOOL send_mailslot(BOOL unique, const char *mailslot,char *buf, size_t len,
 
        memset((char *)&p,'\0',sizeof(p));
 
-       if(ismyip(dest_ip) && (dest_port == DGRAM_PORT)) /* Only if to DGRAM_PORT */
+       if(ismyip_v4(dest_ip) && (dest_port == DGRAM_PORT)) /* Only if to DGRAM_PORT */
                loopback_this_packet = True;
 
        /* generate_name_trn_id(); */ /* Not used, so gone, RJS */
 
        /* DIRECT GROUP or UNIQUE datagram. */
-       dgram->header.msg_type = unique ? 0x10 : 0x11; 
+       dgram->header.msg_type = unique ? 0x10 : 0x11;
        dgram->header.flags.node_type = M_NODE;
        dgram->header.flags.first = True;
        dgram->header.flags.more = False;
@@ -1826,7 +1914,7 @@ BOOL send_mailslot(BOOL unique, const char *mailslot,char *buf, size_t len,
        dgram->header.source_port = DGRAM_PORT;
        dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
        dgram->header.packet_offset = 0;
-  
+
        make_nmb_name(&dgram->source_name,srcname,src_type);
        make_nmb_name(&dgram->dest_name,dstname,dest_type);
 
@@ -1835,7 +1923,13 @@ BOOL send_mailslot(BOOL unique, const char *mailslot,char *buf, size_t len,
        /* Setup the smb part. */
        ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
        memcpy(tmp,ptr,4);
-       set_message(ptr,17,strlen(mailslot) + 1 + len,True);
+
+       if (smb_size + 17*2 + strlen(mailslot) + 1 + len > MAX_DGRAM_SIZE) {
+               DEBUG(0, ("send_mailslot: Cannot write beyond end of packet\n"));
+               return false;
+       }
+
+       cli_set_message(ptr,17,strlen(mailslot) + 1 + len,True);
        memcpy(ptr,tmp,4);
 
        SCVAL(ptr,smb_com,SMBtrans);
@@ -1848,8 +1942,8 @@ BOOL send_mailslot(BOOL unique, const char *mailslot,char *buf, size_t len,
        SSVAL(ptr,smb_vwv16,2);
        p2 = smb_buf(ptr);
        safe_strcpy_base(p2, mailslot, dgram->data, sizeof(dgram->data));
-       p2 = skip_string(p2,1);
-  
+       p2 = skip_string(ptr,MAX_DGRAM_SIZE,p2);
+
        if (((p2+len) > dgram->data+sizeof(dgram->data)) || ((p2+len) < p2)) {
                DEBUG(0, ("send_mailslot: Cannot write beyond end of packet\n"));
                return False;