Rename ASN1_BITFIELD to ASN1_BIT_STRING.
[ira/wip.git] / source3 / libsmb / nmblib.c
index 164f85be7bf13146242d9f1c1abeff504edbf61b..5f3eda44fe2960300e2e2e79fc42016b550c3c57 100644 (file)
@@ -1,32 +1,26 @@
-/* 
+/*
    Unix SMB/CIFS implementation.
    NBT netbios library routines
    Copyright (C) Andrew Tridgell 1994-1998
-   
+   Copyright (C) Jeremy Allison 2007
+
    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,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    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"
 
-extern struct in_addr lastip;
-extern int lastport;
-
-int num_good_sends = 0;
-int num_good_receives = 0;
-
 static const struct opcode_names {
        const char *nmb_opcode_name;
        int opcode;
@@ -83,12 +77,12 @@ static void debug_nmb_res_rec(struct res_rec *res, const char *hdr)
                        unsigned char x = res->rdata[i+j];
                        if (x < 32 || x > 127)
                                x = '.';
-         
+
                        if (i+j >= res->rdlength)
                                break;
                        DEBUGADD(4, ("%c", x));
                }
-      
+
                DEBUGADD(4, ("   hex "));
 
                for (j = 0; j < MAX_NETBIOSNAME_LEN; j++) {
@@ -96,7 +90,7 @@ static void debug_nmb_res_rec(struct res_rec *res, const char *hdr)
                                break;
                        DEBUGADD(4, ("%02X", (unsigned char)res->rdata[i+j]));
                }
-      
+
                DEBUGADD(4, ("\n"));
        }
 }
@@ -110,19 +104,22 @@ void debug_nmb_packet(struct packet_struct *p)
        struct nmb_packet *nmb = &p->packet.nmb;
 
        if( DEBUGLVL( 4 ) ) {
-               dbgtext( "nmb packet from %s(%d) header: id=%d opcode=%s(%d) response=%s\n",
+               dbgtext( "nmb packet from %s(%d) header: id=%d "
+                               "opcode=%s(%d) response=%s\n",
                        inet_ntoa(p->ip), p->port,
                        nmb->header.name_trn_id,
                        lookup_opcode_name(nmb->header.opcode),
                        nmb->header.opcode,
                        BOOLSTR(nmb->header.response) );
-               dbgtext( "    header: flags: bcast=%s rec_avail=%s rec_des=%s trunc=%s auth=%s\n",
+               dbgtext( "    header: flags: bcast=%s rec_avail=%s "
+                               "rec_des=%s trunc=%s auth=%s\n",
                        BOOLSTR(nmb->header.nm_flags.bcast),
                        BOOLSTR(nmb->header.nm_flags.recursion_available),
                        BOOLSTR(nmb->header.nm_flags.recursion_desired),
                        BOOLSTR(nmb->header.nm_flags.trunc),
                        BOOLSTR(nmb->header.nm_flags.authoritative) );
-               dbgtext( "    header: rcode=%d qdcount=%d ancount=%d nscount=%d arcount=%d\n",
+               dbgtext( "    header: rcode=%d qdcount=%d ancount=%d "
+                               "nscount=%d arcount=%d\n",
                        nmb->header.rcode,
                        nmb->header.qdcount,
                        nmb->header.ancount,
@@ -152,21 +149,22 @@ void debug_nmb_packet(struct packet_struct *p)
  Handle "compressed" name pointers.
 ******************************************************************/
 
-static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length,
-                            BOOL *got_pointer,int *ret)
+static bool handle_name_ptrs(unsigned char *ubuf,int *offset,int length,
+                            bool *got_pointer,int *ret)
 {
        int loop_count=0;
-  
+
        while ((ubuf[*offset] & 0xC0) == 0xC0) {
                if (!*got_pointer)
                        (*ret) += 2;
                (*got_pointer)=True;
                (*offset) = ((ubuf[*offset] & ~0xC0)<<8) | ubuf[(*offset)+1];
-               if (loop_count++ == 10 || (*offset) < 0 || (*offset)>(length-2)) {
-                       return(False);
+               if (loop_count++ == 10 ||
+                               (*offset) < 0 || (*offset)>(length-2)) {
+                       return False;
                }
        }
-       return(True);
+       return True;
 }
 
 /*******************************************************************
@@ -179,17 +177,17 @@ static int parse_nmb_name(char *inbuf,int ofs,int length, struct nmb_name *name)
        int m,n=0;
        unsigned char *ubuf = (unsigned char *)inbuf;
        int ret = 0;
-       BOOL got_pointer=False;
+       bool got_pointer=False;
        int loop_count=0;
        int offset = ofs;
 
        if (length - offset < 2)
-               return(0);  
+               return(0);
 
        /* handle initial name pointers */
        if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
                return(0);
-  
+
        m = ubuf[offset];
 
        if (!m)
@@ -215,14 +213,15 @@ static int parse_nmb_name(char *inbuf,int ofs,int length, struct nmb_name *name)
        name->name[n] = 0;
 
        if (n==MAX_NETBIOSNAME_LEN) {
-               /* parse out the name type, its always in the 16th byte of the name */
+               /* parse out the name type, its always
+                * in the 16th byte of the name */
                name->name_type = ((unsigned char)name->name[15]) & 0xff;
-  
+
                /* remove trailing spaces */
                name->name[15] = 0;
                n = 14;
                while (n && name->name[n]==' ')
-                       name->name[n--] = 0;  
+                       name->name[n--] = 0;
        }
 
        /* now the domain parts (if any) */
@@ -254,7 +253,7 @@ static int parse_nmb_name(char *inbuf,int ofs,int length, struct nmb_name *name)
                if (loop_count++ == 10)
                        return 0;
        }
-       name->scope[n++] = 0;  
+       name->scope[n++] = 0;
 
        return(ret);
 }
@@ -265,11 +264,12 @@ static int parse_nmb_name(char *inbuf,int ofs,int length, struct nmb_name *name)
  [15 bytes name + padding][1 byte name type].
 ****************************************************************************/
 
-static void put_name(char *dest, const char *name, int pad, unsigned int name_type)
+void put_name(char *dest, const char *name, int pad, unsigned int name_type)
 {
        size_t len = strlen(name);
 
-       memcpy(dest, name, (len < MAX_NETBIOSNAME_LEN) ? len : MAX_NETBIOSNAME_LEN - 1);
+       memcpy(dest, name, (len < MAX_NETBIOSNAME_LEN) ?
+                       len : MAX_NETBIOSNAME_LEN - 1);
        if (len < MAX_NETBIOSNAME_LEN - 1) {
                memset(dest + len, pad, MAX_NETBIOSNAME_LEN - 1 - len);
        }
@@ -283,6 +283,8 @@ static void put_name(char *dest, const char *name, int pad, unsigned int name_ty
  Compressed names are really weird. The "compression" doubles the
  size. The idea is that it also means that compressed names conform
  to the doman name system. See RFC1002.
+
+ If buf == NULL this is a length calculation.
 ******************************************************************/
 
 static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
@@ -298,61 +300,70 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
                put_name(buf1, name->name, ' ', name->name_type);
        }
 
-       buf[offset] = 0x20;
+       if (buf) {
+               buf[offset] = 0x20;
+       }
 
        ret = 34;
 
        for (m=0;m<MAX_NETBIOSNAME_LEN;m++) {
-               buf[offset+1+2*m] = 'A' + ((buf1[m]>>4)&0xF);
-               buf[offset+2+2*m] = 'A' + (buf1[m]&0xF);
+               if (buf) {
+                       buf[offset+1+2*m] = 'A' + ((buf1[m]>>4)&0xF);
+                       buf[offset+2+2*m] = 'A' + (buf1[m]&0xF);
+               }
        }
        offset += 33;
 
-       buf[offset] = 0;
+       if (buf) {
+               buf[offset] = 0;
+       }
 
        if (name->scope[0]) {
                /* XXXX this scope handling needs testing */
                ret += strlen(name->scope) + 1;
-               safe_strcpy(&buf[offset+1],name->scope,sizeof(name->scope));  
-  
-               p = &buf[offset+1];
-               while ((p = strchr_m(p,'.'))) {
-                       buf[offset] = PTR_DIFF(p,&buf[offset+1]);
-                       offset += (buf[offset] + 1);
+               if (buf) {
+                       safe_strcpy(&buf[offset+1],name->scope,
+                                       sizeof(name->scope));
+
                        p = &buf[offset+1];
+                       while ((p = strchr_m(p,'.'))) {
+                               buf[offset] = PTR_DIFF(p,&buf[offset+1]);
+                               offset += (buf[offset] + 1);
+                               p = &buf[offset+1];
+                       }
+                       buf[offset] = strlen(&buf[offset+1]);
                }
-               buf[offset] = strlen(&buf[offset+1]);
        }
 
-       return(ret);
+       return ret;
 }
 
 /*******************************************************************
  Useful for debugging messages.
 ******************************************************************/
 
-char *nmb_namestr(struct nmb_name *n)
+char *nmb_namestr(const struct nmb_name *n)
 {
-       static int i=0;
-       static fstring ret[4];
        fstring name;
-       char *p = ret[i];
+       char *result;
 
        pull_ascii_fstring(name, n->name);
        if (!n->scope[0])
-               slprintf(p,sizeof(fstring)-1, "%s<%02x>",name,n->name_type);
+               result = talloc_asprintf(talloc_tos(), "%s<%02x>", name,
+                                        n->name_type);
        else
-               slprintf(p,sizeof(fstring)-1, "%s<%02x>.%s",name,n->name_type,n->scope);
+               result = talloc_asprintf(talloc_tos(), "%s<%02x>.%s", name,
+                                        n->name_type, n->scope);
 
-       i = (i+1)%4;
-       return(p);
+       SMB_ASSERT(result != NULL);
+       return result;
 }
 
 /*******************************************************************
  Allocate and parse some resource records.
 ******************************************************************/
 
-static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length,
+static bool parse_alloc_res_rec(char *inbuf,int *offset,int length,
                                struct res_rec **recs, int count)
 {
        int i;
@@ -364,7 +375,8 @@ static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length,
        memset((char *)*recs,'\0',sizeof(**recs)*count);
 
        for (i=0;i<count;i++) {
-               int l = parse_nmb_name(inbuf,*offset,length,&(*recs)[i].rr_name);
+               int l = parse_nmb_name(inbuf,*offset,length,
+                               &(*recs)[i].rr_name);
                (*offset) += l;
                if (!l || (*offset)+10 > length) {
                        SAFE_FREE(*recs);
@@ -375,19 +387,20 @@ static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length,
                (*recs)[i].ttl = RIVAL(inbuf,(*offset)+4);
                (*recs)[i].rdlength = RSVAL(inbuf,(*offset)+8);
                (*offset) += 10;
-               if ((*recs)[i].rdlength>sizeof((*recs)[i].rdata) || 
+               if ((*recs)[i].rdlength>sizeof((*recs)[i].rdata) ||
                                (*offset)+(*recs)[i].rdlength > length) {
                        SAFE_FREE(*recs);
                        return(False);
                }
                memcpy((*recs)[i].rdata,inbuf+(*offset),(*recs)[i].rdlength);
-               (*offset) += (*recs)[i].rdlength;    
+               (*offset) += (*recs)[i].rdlength;
        }
        return(True);
 }
 
 /*******************************************************************
  Put a resource record into a packet.
+ If buf == NULL this is a length calculation.
 ******************************************************************/
 
 static int put_res_rec(char *buf,int offset,struct res_rec *recs,int count)
@@ -399,48 +412,58 @@ static int put_res_rec(char *buf,int offset,struct res_rec *recs,int count)
                int l = put_nmb_name(buf,offset,&recs[i].rr_name);
                offset += l;
                ret += l;
-               RSSVAL(buf,offset,recs[i].rr_type);
-               RSSVAL(buf,offset+2,recs[i].rr_class);
-               RSIVAL(buf,offset+4,recs[i].ttl);
-               RSSVAL(buf,offset+8,recs[i].rdlength);
-               memcpy(buf+offset+10,recs[i].rdata,recs[i].rdlength);
+               if (buf) {
+                       RSSVAL(buf,offset,recs[i].rr_type);
+                       RSSVAL(buf,offset+2,recs[i].rr_class);
+                       RSIVAL(buf,offset+4,recs[i].ttl);
+                       RSSVAL(buf,offset+8,recs[i].rdlength);
+                       memcpy(buf+offset+10,recs[i].rdata,recs[i].rdlength);
+               }
                offset += 10+recs[i].rdlength;
                ret += 10+recs[i].rdlength;
        }
 
-       return(ret);
+       return ret;
 }
 
 /*******************************************************************
  Put a compressed name pointer record into a packet.
+ If buf == NULL this is a length calculation.
 ******************************************************************/
 
-static int put_compressed_name_ptr(unsigned char *buf,int offset,struct res_rec *rec,int ptr_offset)
-{  
+static int put_compressed_name_ptr(unsigned char *buf,
+                               int offset,
+                               struct res_rec *rec,
+                               int ptr_offset)
+{
        int ret=0;
-       buf[offset] = (0xC0 | ((ptr_offset >> 8) & 0xFF));
-       buf[offset+1] = (ptr_offset & 0xFF);
+       if (buf) {
+               buf[offset] = (0xC0 | ((ptr_offset >> 8) & 0xFF));
+               buf[offset+1] = (ptr_offset & 0xFF);
+       }
        offset += 2;
        ret += 2;
-       RSSVAL(buf,offset,rec->rr_type);
-       RSSVAL(buf,offset+2,rec->rr_class);
-       RSIVAL(buf,offset+4,rec->ttl);
-       RSSVAL(buf,offset+8,rec->rdlength);
-       memcpy(buf+offset+10,rec->rdata,rec->rdlength);
+       if (buf) {
+               RSSVAL(buf,offset,rec->rr_type);
+               RSSVAL(buf,offset+2,rec->rr_class);
+               RSIVAL(buf,offset+4,rec->ttl);
+               RSSVAL(buf,offset+8,rec->rdlength);
+               memcpy(buf+offset+10,rec->rdata,rec->rdlength);
+       }
        offset += 10+rec->rdlength;
        ret += 10+rec->rdlength;
-    
-       return(ret);
+
+       return ret;
 }
 
 /*******************************************************************
- Parse a dgram packet. Return False if the packet can't be parsed 
+ Parse a dgram packet. Return False if the packet can't be parsed
  or is invalid for some reason, True otherwise.
 
  This is documented in section 4.4.1 of RFC1002.
 ******************************************************************/
 
-static BOOL parse_dgram(char *inbuf,int length,struct dgram_packet *dgram)
+static bool parse_dgram(char *inbuf,int length,struct dgram_packet *dgram)
 {
        int offset;
        int flags;
@@ -467,19 +490,22 @@ static BOOL parse_dgram(char *inbuf,int length,struct dgram_packet *dgram)
 
        if (dgram->header.msg_type == 0x10 ||
                        dgram->header.msg_type == 0x11 ||
-                       dgram->header.msg_type == 0x12) {      
-               offset += parse_nmb_name(inbuf,offset,length,&dgram->source_name);
-               offset += parse_nmb_name(inbuf,offset,length,&dgram->dest_name);
+                       dgram->header.msg_type == 0x12) {
+               offset += parse_nmb_name(inbuf,offset,length,
+                               &dgram->source_name);
+               offset += parse_nmb_name(inbuf,offset,length,
+                               &dgram->dest_name);
        }
 
-       if (offset >= length || (length-offset > sizeof(dgram->data))) 
+       if (offset >= length || (length-offset > sizeof(dgram->data)))
                return(False);
 
        dgram->datasize = length-offset;
        memcpy(dgram->data,inbuf+offset,dgram->datasize);
 
        /* Paranioa. Ensure the last 2 bytes in the dgram buffer are
-          zero. This should be true anyway, just enforce it for paranioa sake. JRA. */
+          zero. This should be true anyway, just enforce it for
+          paranioa sake. JRA. */
        SMB_ASSERT(dgram->datasize <= (sizeof(dgram->data)-2));
        memset(&dgram->data[sizeof(dgram->data)-2], '\0', 2);
 
@@ -487,11 +513,11 @@ static BOOL parse_dgram(char *inbuf,int length,struct dgram_packet *dgram)
 }
 
 /*******************************************************************
- Parse a nmb packet. Return False if the packet can't be parsed 
+ Parse a nmb packet. Return False if the packet can't be parsed
  or is invalid for some reason, True otherwise.
 ******************************************************************/
 
-static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
+static bool parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
 {
        int nm_flags,offset;
 
@@ -512,15 +538,16 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
        nmb->header.nm_flags.recursion_available = (nm_flags&8)?True:False;
        nmb->header.nm_flags.recursion_desired = (nm_flags&0x10)?True:False;
        nmb->header.nm_flags.trunc = (nm_flags&0x20)?True:False;
-       nmb->header.nm_flags.authoritative = (nm_flags&0x40)?True:False;  
+       nmb->header.nm_flags.authoritative = (nm_flags&0x40)?True:False;
        nmb->header.rcode = CVAL(inbuf,3) & 0xF;
        nmb->header.qdcount = RSVAL(inbuf,4);
        nmb->header.ancount = RSVAL(inbuf,6);
        nmb->header.nscount = RSVAL(inbuf,8);
        nmb->header.arcount = RSVAL(inbuf,10);
-  
+
        if (nmb->header.qdcount) {
-               offset = parse_nmb_name(inbuf,12,length,&nmb->question.question_name);
+               offset = parse_nmb_name(inbuf,12,length,
+                               &nmb->question.question_name);
                if (!offset)
                        return(False);
 
@@ -535,16 +562,19 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
        }
 
        /* and any resource records */
-       if (nmb->header.ancount && !parse_alloc_res_rec(inbuf,&offset,length,&nmb->answers,
+       if (nmb->header.ancount &&
+                       !parse_alloc_res_rec(inbuf,&offset,length,&nmb->answers,
                                        nmb->header.ancount))
                return(False);
 
-       if (nmb->header.nscount && !parse_alloc_res_rec(inbuf,&offset,length,&nmb->nsrecs,
+       if (nmb->header.nscount &&
+                       !parse_alloc_res_rec(inbuf,&offset,length,&nmb->nsrecs,
                                        nmb->header.nscount))
                return(False);
-  
-       if (nmb->header.arcount && !parse_alloc_res_rec(inbuf,&offset,length,&nmb->additional,
-                                       nmb->header.arcount))
+
+       if (nmb->header.arcount &&
+                       !parse_alloc_res_rec(inbuf,&offset,length,
+                               &nmb->additional, nmb->header.arcount))
                return(False);
 
        return(True);
@@ -555,7 +585,7 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
 ******************************************************************/
 
 static struct packet_struct *copy_nmb_packet(struct packet_struct *packet)
-{  
+{
        struct nmb_packet *nmb;
        struct nmb_packet *copy_nmb;
        struct packet_struct *pkt_copy;
@@ -583,21 +613,24 @@ static struct packet_struct *copy_nmb_packet(struct packet_struct *packet)
        /* Now copy any resource records. */
 
        if (nmb->answers) {
-               if((copy_nmb->answers = SMB_MALLOC_ARRAY(struct res_rec,nmb->header.ancount)) == NULL)
+               if((copy_nmb->answers = SMB_MALLOC_ARRAY(
+                               struct res_rec,nmb->header.ancount)) == NULL)
                        goto free_and_exit;
-               memcpy((char *)copy_nmb->answers, (char *)nmb->answers, 
+               memcpy((char *)copy_nmb->answers, (char *)nmb->answers,
                                nmb->header.ancount * sizeof(struct res_rec));
        }
        if (nmb->nsrecs) {
-               if((copy_nmb->nsrecs = SMB_MALLOC_ARRAY(struct res_rec, nmb->header.nscount)) == NULL)
+               if((copy_nmb->nsrecs = SMB_MALLOC_ARRAY(
+                               struct res_rec, nmb->header.nscount)) == NULL)
                        goto free_and_exit;
-               memcpy((char *)copy_nmb->nsrecs, (char *)nmb->nsrecs, 
+               memcpy((char *)copy_nmb->nsrecs, (char *)nmb->nsrecs,
                                nmb->header.nscount * sizeof(struct res_rec));
        }
        if (nmb->additional) {
-               if((copy_nmb->additional = SMB_MALLOC_ARRAY(struct res_rec, nmb->header.arcount)) == NULL)
+               if((copy_nmb->additional = SMB_MALLOC_ARRAY(
+                               struct res_rec, nmb->header.arcount)) == NULL)
                        goto free_and_exit;
-               memcpy((char *)copy_nmb->additional, (char *)nmb->additional, 
+               memcpy((char *)copy_nmb->additional, (char *)nmb->additional,
                                nmb->header.arcount * sizeof(struct res_rec));
        }
 
@@ -619,7 +652,7 @@ static struct packet_struct *copy_nmb_packet(struct packet_struct *packet)
 ******************************************************************/
 
 static struct packet_struct *copy_dgram_packet(struct packet_struct *packet)
-{ 
+{
        struct packet_struct *pkt_copy;
 
        if(( pkt_copy = SMB_MALLOC_P(struct packet_struct)) == NULL) {
@@ -644,20 +677,20 @@ static struct packet_struct *copy_dgram_packet(struct packet_struct *packet)
 ******************************************************************/
 
 struct packet_struct *copy_packet(struct packet_struct *packet)
-{  
+{
        if(packet->packet_type == NMB_PACKET)
                return copy_nmb_packet(packet);
        else if (packet->packet_type == DGRAM_PACKET)
                return copy_dgram_packet(packet);
        return NULL;
 }
+
 /*******************************************************************
  Free up any resources associated with an nmb packet.
 ******************************************************************/
 
 static void free_nmb_packet(struct nmb_packet *nmb)
-{  
+{
        SAFE_FREE(nmb->answers);
        SAFE_FREE(nmb->nsrecs);
        SAFE_FREE(nmb->additional);
@@ -668,7 +701,7 @@ static void free_nmb_packet(struct nmb_packet *nmb)
 ******************************************************************/
 
 static void free_dgram_packet(struct dgram_packet *nmb)
-{  
+{
        /* We have nothing to do for a dgram packet. */
 }
 
@@ -677,8 +710,8 @@ static void free_dgram_packet(struct dgram_packet *nmb)
 ******************************************************************/
 
 void free_packet(struct packet_struct *packet)
-{  
-       if (packet->locked) 
+{
+       if (packet->locked)
                return;
        if (packet->packet_type == NMB_PACKET)
                free_nmb_packet(&packet->packet.nmb);
@@ -693,19 +726,23 @@ void free_packet(struct packet_struct *packet)
 ******************************************************************/
 
 struct packet_struct *parse_packet(char *buf,int length,
-                                  enum packet_type packet_type)
+                                  enum packet_type packet_type,
+                                  struct in_addr ip,
+                                  int port)
 {
        struct packet_struct *p;
-       BOOL ok=False;
+       bool ok=False;
 
        p = SMB_MALLOC_P(struct packet_struct);
        if (!p)
                return(NULL);
 
+       ZERO_STRUCTP(p);        /* initialize for possible padding */
+
        p->next = NULL;
        p->prev = NULL;
-       p->ip = lastip;
-       p->port = lastport;
+       p->ip = ip;
+       p->port = port;
        p->locked = False;
        p->timestamp = time(NULL);
        p->packet_type = packet_type;
@@ -714,7 +751,7 @@ struct packet_struct *parse_packet(char *buf,int length,
        case NMB_PACKET:
                ok = parse_nmb(buf,length,&p->packet.nmb);
                break;
-               
+
        case DGRAM_PACKET:
                ok = parse_dgram(buf,length,&p->packet.dgram);
                break;
@@ -736,34 +773,39 @@ struct packet_struct *parse_packet(char *buf,int length,
 struct packet_struct *read_packet(int fd,enum packet_type packet_type)
 {
        struct packet_struct *packet;
+       struct sockaddr_storage sa;
+       struct sockaddr_in *si = (struct sockaddr_in *)&sa;
        char buf[MAX_DGRAM_SIZE];
        int length;
-       
-       length = read_udp_socket(fd,buf,sizeof(buf));
-       if (length < MIN_DGRAM_SIZE)
-               return(NULL);
-       
-       packet = parse_packet(buf, length, packet_type);
+
+       length = read_udp_v4_socket(fd,buf,sizeof(buf),&sa);
+       if (length < MIN_DGRAM_SIZE || sa.ss_family != AF_INET) {
+               return NULL;
+       }
+
+       packet = parse_packet(buf,
+                       length,
+                       packet_type,
+                       si->sin_addr,
+                       ntohs(si->sin_port));
        if (!packet)
                return NULL;
 
        packet->fd = fd;
-       
-       num_good_receives++;
-       
+
        DEBUG(5,("Received a packet of len %d from (%s) port %d\n",
                 length, inet_ntoa(packet->ip), packet->port ) );
-       
+
        return(packet);
 }
-                                        
+
 /*******************************************************************
  Send a udp packet on a already open socket.
 ******************************************************************/
 
-static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
+static bool send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
 {
-       BOOL ret = False;
+       bool ret = False;
        int i;
        struct sockaddr_in sock_out;
 
@@ -772,16 +814,17 @@ static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
        putip((char *)&sock_out.sin_addr,(char *)&ip);
        sock_out.sin_port = htons( port );
        sock_out.sin_family = AF_INET;
-  
+
        DEBUG( 5, ( "Sending a packet of len %d to (%s) on port %d\n",
                        len, inet_ntoa(ip), port ) );
 
        /*
         * Patch to fix asynch error notifications from Linux kernel.
         */
-       
+
        for (i = 0; i < 5; i++) {
-               ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out, sizeof(sock_out)) >= 0);
+               ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out,
+                                       sizeof(sock_out)) >= 0);
                if (ret || errno != ECONNREFUSED)
                        break;
        }
@@ -790,56 +833,45 @@ static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
                DEBUG(0,("Packet send failed to %s(%d) ERRNO=%s\n",
                        inet_ntoa(ip),port,strerror(errno)));
 
-       if (ret)
-               num_good_sends++;
-
        return(ret);
 }
 
 /*******************************************************************
  Build a dgram packet ready for sending.
-
- XXXX This currently doesn't handle packets too big for one
- datagram. It should split them and use the packet_offset, more and
- first flags to handle the fragmentation. Yuck.
-
-   [...but it isn't clear that we would ever need to send a
-   a fragmented NBT Datagram.  The IP layer does its own
-   fragmentation to ensure that messages can fit into the path
-   MTU.  It *is* important to be able to receive and rebuild
-   fragmented NBT datagrams, just in case someone out there
-   really has implemented this 'feature'.  crh -)------ ]
-
+ If buf == NULL this is a length calculation.
 ******************************************************************/
 
-static int build_dgram(char *buf,struct packet_struct *p)
+static int build_dgram(char *buf, size_t len, struct dgram_packet *dgram)
 {
-       struct dgram_packet *dgram = &p->packet.dgram;
        unsigned char *ubuf = (unsigned char *)buf;
        int offset=0;
 
        /* put in the header */
-       ubuf[0] = dgram->header.msg_type;
-       ubuf[1] = (((int)dgram->header.flags.node_type)<<2);
-       if (dgram->header.flags.more)
-               ubuf[1] |= 1;
-       if (dgram->header.flags.first)
-               ubuf[1] |= 2;
-       RSSVAL(ubuf,2,dgram->header.dgm_id);
-       putip(ubuf+4,(char *)&dgram->header.source_ip);
-       RSSVAL(ubuf,8,dgram->header.source_port);
-       RSSVAL(ubuf,12,dgram->header.packet_offset);
+       if (buf) {
+               ubuf[0] = dgram->header.msg_type;
+               ubuf[1] = (((int)dgram->header.flags.node_type)<<2);
+               if (dgram->header.flags.more)
+                       ubuf[1] |= 1;
+               if (dgram->header.flags.first)
+                       ubuf[1] |= 2;
+               RSSVAL(ubuf,2,dgram->header.dgm_id);
+               putip(ubuf+4,(char *)&dgram->header.source_ip);
+               RSSVAL(ubuf,8,dgram->header.source_port);
+               RSSVAL(ubuf,12,dgram->header.packet_offset);
+       }
 
        offset = 14;
 
        if (dgram->header.msg_type == 0x10 ||
                        dgram->header.msg_type == 0x11 ||
-                       dgram->header.msg_type == 0x12) {      
+                       dgram->header.msg_type == 0x12) {
                offset += put_nmb_name((char *)ubuf,offset,&dgram->source_name);
                offset += put_nmb_name((char *)ubuf,offset,&dgram->dest_name);
        }
 
-       memcpy(ubuf+offset,dgram->data,dgram->datasize);
+       if (buf) {
+               memcpy(ubuf+offset,dgram->data,dgram->datasize);
+       }
        offset += dgram->datasize;
 
        /* automatically set the dgm_length
@@ -847,9 +879,11 @@ static int build_dgram(char *buf,struct packet_struct *p)
         *       include the fourteen-byte header. crh
         */
        dgram->header.dgm_length = (offset - 14);
-       RSSVAL(ubuf,10,dgram->header.dgm_length); 
+       if (buf) {
+               RSSVAL(ubuf,10,dgram->header.dgm_length);
+       }
 
-       return(offset);
+       return offset;
 }
 
 /*******************************************************************
@@ -871,7 +905,7 @@ void make_nmb_name( struct nmb_name *n, const char *name, int type)
   Compare two nmb names
 ******************************************************************/
 
-BOOL nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2)
+bool nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2)
 {
        return ((n1->name_type == n2->name_type) &&
                strequal(n1->name ,n2->name ) &&
@@ -880,59 +914,89 @@ BOOL nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2)
 
 /*******************************************************************
  Build a nmb packet ready for sending.
-
- XXXX this currently relies on not being passed something that expands
- to a packet too big for the buffer. Eventually this should be
- changed to set the trunc bit so the receiver can request the rest
- via tcp (when that becomes supported)
+ If buf == NULL this is a length calculation.
 ******************************************************************/
 
-static int build_nmb(char *buf,struct packet_struct *p)
+static int build_nmb(char *buf, size_t len, struct nmb_packet *nmb)
 {
-       struct nmb_packet *nmb = &p->packet.nmb;
        unsigned char *ubuf = (unsigned char *)buf;
        int offset=0;
 
+       if (len && len < 12) {
+               return 0;
+       }
+
        /* put in the header */
-       RSSVAL(ubuf,offset,nmb->header.name_trn_id);
-       ubuf[offset+2] = (nmb->header.opcode & 0xF) << 3;
-       if (nmb->header.response)
-               ubuf[offset+2] |= (1<<7);
-       if (nmb->header.nm_flags.authoritative && 
-                       nmb->header.response)
-               ubuf[offset+2] |= 0x4;
-       if (nmb->header.nm_flags.trunc)
-               ubuf[offset+2] |= 0x2;
-       if (nmb->header.nm_flags.recursion_desired)
-               ubuf[offset+2] |= 0x1;
-       if (nmb->header.nm_flags.recursion_available &&
-                       nmb->header.response)
-               ubuf[offset+3] |= 0x80;
-       if (nmb->header.nm_flags.bcast)
-               ubuf[offset+3] |= 0x10;
-       ubuf[offset+3] |= (nmb->header.rcode & 0xF);
-
-       RSSVAL(ubuf,offset+4,nmb->header.qdcount);
-       RSSVAL(ubuf,offset+6,nmb->header.ancount);
-       RSSVAL(ubuf,offset+8,nmb->header.nscount);
-       RSSVAL(ubuf,offset+10,nmb->header.arcount);
-  
+       if (buf) {
+               RSSVAL(ubuf,offset,nmb->header.name_trn_id);
+               ubuf[offset+2] = (nmb->header.opcode & 0xF) << 3;
+               if (nmb->header.response)
+                       ubuf[offset+2] |= (1<<7);
+               if (nmb->header.nm_flags.authoritative &&
+                               nmb->header.response)
+                       ubuf[offset+2] |= 0x4;
+               if (nmb->header.nm_flags.trunc)
+                       ubuf[offset+2] |= 0x2;
+               if (nmb->header.nm_flags.recursion_desired)
+                       ubuf[offset+2] |= 0x1;
+               if (nmb->header.nm_flags.recursion_available &&
+                               nmb->header.response)
+                       ubuf[offset+3] |= 0x80;
+               if (nmb->header.nm_flags.bcast)
+                       ubuf[offset+3] |= 0x10;
+               ubuf[offset+3] |= (nmb->header.rcode & 0xF);
+
+               RSSVAL(ubuf,offset+4,nmb->header.qdcount);
+               RSSVAL(ubuf,offset+6,nmb->header.ancount);
+               RSSVAL(ubuf,offset+8,nmb->header.nscount);
+               RSSVAL(ubuf,offset+10,nmb->header.arcount);
+       }
+
        offset += 12;
        if (nmb->header.qdcount) {
                /* XXXX this doesn't handle a qdcount of > 1 */
-               offset += put_nmb_name((char *)ubuf,offset,&nmb->question.question_name);
-               RSSVAL(ubuf,offset,nmb->question.question_type);
-               RSSVAL(ubuf,offset+2,nmb->question.question_class);
+               if (len) {
+                       /* Length check. */
+                       int extra = put_nmb_name(NULL,offset,
+                                       &nmb->question.question_name);
+                       if (offset + extra > len) {
+                               return 0;
+                       }
+               }
+               offset += put_nmb_name((char *)ubuf,offset,
+                               &nmb->question.question_name);
+               if (buf) {
+                       RSSVAL(ubuf,offset,nmb->question.question_type);
+                       RSSVAL(ubuf,offset+2,nmb->question.question_class);
+               }
                offset += 4;
        }
 
-       if (nmb->header.ancount)
+       if (nmb->header.ancount) {
+               if (len) {
+                       /* Length check. */
+                       int extra = put_res_rec(NULL,offset,nmb->answers,
+                                       nmb->header.ancount);
+                       if (offset + extra > len) {
+                               return 0;
+                       }
+               }
                offset += put_res_rec((char *)ubuf,offset,nmb->answers,
                                nmb->header.ancount);
+       }
 
-       if (nmb->header.nscount)
+       if (nmb->header.nscount) {
+               if (len) {
+                       /* Length check. */
+                       int extra = put_res_rec(NULL,offset,nmb->nsrecs,
+                               nmb->header.nscount);
+                       if (offset + extra > len) {
+                               return 0;
+                       }
+               }
                offset += put_res_rec((char *)ubuf,offset,nmb->nsrecs,
                                nmb->header.nscount);
+       }
 
        /*
         * The spec says we must put compressed name pointers
@@ -942,37 +1006,53 @@ static int build_nmb(char *buf,struct packet_struct *p)
         */
 
        if((nmb->header.response == False) &&
-                       ((nmb->header.opcode == NMB_NAME_REG_OPCODE) ||
-                       (nmb->header.opcode == NMB_NAME_RELEASE_OPCODE) ||
-                       (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) ||
-                       (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9) ||
-                       (nmb->header.opcode == NMB_NAME_MULTIHOMED_REG_OPCODE)) &&
-                       (nmb->header.arcount == 1)) {
-
-               offset += put_compressed_name_ptr(ubuf,offset,nmb->additional,12);
-
+               ((nmb->header.opcode == NMB_NAME_REG_OPCODE) ||
+               (nmb->header.opcode == NMB_NAME_RELEASE_OPCODE) ||
+               (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) ||
+               (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9) ||
+               (nmb->header.opcode == NMB_NAME_MULTIHOMED_REG_OPCODE)) &&
+               (nmb->header.arcount == 1)) {
+
+               if (len) {
+                       /* Length check. */
+                       int extra = put_compressed_name_ptr(NULL,offset,
+                                       nmb->additional,12);
+                       if (offset + extra > len) {
+                               return 0;
+                       }
+               }
+               offset += put_compressed_name_ptr(ubuf,offset,
+                               nmb->additional,12);
        } else if (nmb->header.arcount) {
+               if (len) {
+                       /* Length check. */
+                       int extra = put_res_rec(NULL,offset,nmb->additional,
+                               nmb->header.arcount);
+                       if (offset + extra > len) {
+                               return 0;
+                       }
+               }
                offset += put_res_rec((char *)ubuf,offset,nmb->additional,
-                       nmb->header.arcount);  
+                       nmb->header.arcount);
        }
-       return(offset);
+       return offset;
 }
 
 /*******************************************************************
  Linearise a packet.
 ******************************************************************/
 
-int build_packet(char *buf, struct packet_struct *p)
+int build_packet(char *buf, size_t buflen, struct packet_struct *p)
 {
        int len = 0;
 
        switch (p->packet_type) {
        case NMB_PACKET:
-               len = build_nmb(buf,p);
+               len = build_nmb(buf,buflen,&p->packet.nmb);
                break;
 
        case DGRAM_PACKET:
-               len = build_dgram(buf,p);
+               len = build_dgram(buf,buflen,&p->packet.dgram);
                break;
        }
 
@@ -983,14 +1063,14 @@ int build_packet(char *buf, struct packet_struct *p)
  Send a packet_struct.
 ******************************************************************/
 
-BOOL send_packet(struct packet_struct *p)
+bool send_packet(struct packet_struct *p)
 {
        char buf[1024];
        int len=0;
 
        memset(buf,'\0',sizeof(buf));
 
-       len = build_packet(buf, p);
+       len = build_packet(buf, sizeof(buf), p);
 
        if (!len)
                return(False);
@@ -1016,16 +1096,17 @@ struct packet_struct *receive_packet(int fd,enum packet_type type,int t)
 
        if ((ret = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout)) == -1) {
                /* errno should be EBADF or EINVAL. */
-               DEBUG(0,("select returned -1, errno = %s (%d)\n", strerror(errno), errno));
+               DEBUG(0,("select returned -1, errno = %s (%d)\n",
+                                       strerror(errno), errno));
                return NULL;
        }
 
        if (ret == 0) /* timeout */
                return NULL;
 
-       if (FD_ISSET(fd,&fds)) 
+       if (FD_ISSET(fd,&fds))
                return(read_packet(fd,type));
-       
+
        return(NULL);
 }
 
@@ -1058,7 +1139,8 @@ struct packet_struct *receive_nmb_packet(int fd, int t, int trn_id)
  The timeout is in milliseconds.
 ***************************************************************************/
 
-struct packet_struct *receive_dgram_packet(int fd, int t, const char *mailslot_name)
+struct packet_struct *receive_dgram_packet(int fd, int t,
+               const char *mailslot_name)
 {
        struct packet_struct *p;
 
@@ -1078,7 +1160,7 @@ struct packet_struct *receive_dgram_packet(int fd, int t, const char *mailslot_n
  See if a datagram has the right mailslot name.
 ***************************************************************************/
 
-BOOL match_mailslot_name(struct packet_struct *p, const char *mailslot_name)
+bool match_mailslot_name(struct packet_struct *p, const char *mailslot_name)
 {
        struct dgram_packet *dgram = &p->packet.dgram;
        char *buf;
@@ -1096,27 +1178,28 @@ BOOL match_mailslot_name(struct packet_struct *p, const char *mailslot_name)
 }
 
 /****************************************************************************
- Return the number of bits that match between two 4 character buffers
+ Return the number of bits that match between two len character buffers
 ***************************************************************************/
 
-int matching_quad_bits(unsigned char *p1, unsigned char *p2)
+int matching_len_bits(unsigned char *p1, unsigned char *p2, size_t len)
 {
-       int i, j, ret = 0;
-       for (i=0; i<4; i++) {
+       size_t i, j;
+       int ret = 0;
+       for (i=0; i<len; i++) {
                if (p1[i] != p2[i])
                        break;
                ret += 8;
        }
 
-       if (i==4)
+       if (i==len)
                return ret;
 
        for (j=0; j<8; j++) {
                if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j))))
                        break;
                ret++;
-       }       
-       
+       }
+
        return ret;
 }
 
@@ -1128,7 +1211,8 @@ static unsigned char sort_ip[4];
 
 static int name_query_comp(unsigned char *p1, unsigned char *p2)
 {
-       return matching_quad_bits(p2+2, sort_ip) - matching_quad_bits(p1+2, sort_ip);
+       return matching_len_bits(p2+2, sort_ip, 4) -
+               matching_len_bits(p1+2, sort_ip, 4);
 }
 
 /****************************************************************************
@@ -1146,40 +1230,6 @@ void sort_query_replies(char *data, int n, struct in_addr ip)
        qsort(data, n, 6, QSORT_CAST name_query_comp);
 }
 
-/*******************************************************************
- Convert, possibly using a stupid microsoft-ism which has destroyed
- the transport independence of netbios (for CIFS vendors that usually
- use the Win95-type methods, not for NT to NT communication, which uses
- DCE/RPC and therefore full-length unicode strings...) a dns name into
- a netbios name.
-
- The netbios name (NOT necessarily null-terminated) is truncated to 15
- characters.
-
- ******************************************************************/
-
-char *dns_to_netbios_name(const char *dns_name)
-{
-       static nstring netbios_name;
-       int i;
-       StrnCpy(netbios_name, dns_name, MAX_NETBIOSNAME_LEN-1);
-       netbios_name[15] = 0;
-       
-       /* ok.  this is because of a stupid microsoft-ism.  if the called host
-          name contains a '.', microsoft clients expect you to truncate the
-          netbios name up to and including the '.'  this even applies, by
-          mistake, to workgroup (domain) names, which is _really_ daft.
-        */
-       for (i = 0; i < 15; i++) {
-               if (netbios_name[i] == '.') {
-                       netbios_name[i] = 0;
-                       break;
-               }
-       }
-
-       return netbios_name;
-}
-
 /****************************************************************************
  Interpret the weird netbios "name" into a unix fstring. Return the name type.
 ****************************************************************************/
@@ -1229,12 +1279,19 @@ static int name_interpret(char *in, fstring name)
  Note:  <Out> must be (33 + strlen(scope) + 2) bytes long, at minimum.
 ****************************************************************************/
 
-int name_mangle( char *In, char *Out, char name_type )
+char *name_mangle(TALLOC_CTX *mem_ctx, char *In, char name_type)
 {
        int   i;
        int   len;
        nstring buf;
-       char *p = Out;
+       char *result;
+       char *p;
+
+       result = talloc_array(mem_ctx, char, 33 + strlen(global_scope()) + 2);
+       if (result == NULL) {
+               return NULL;
+       }
+       p = result;
 
        /* Safely copy the input string, In, into buf[]. */
        if (strcmp(In,"*") == 0)
@@ -1271,7 +1328,7 @@ int name_mangle( char *In, char *Out, char name_type )
                                p[0] = len;
                                if( len > 0 )
                                        p[len+1] = 0;
-                               return( name_len(Out) );
+                               return result;
                        case '.':
                                p[0] = len;
                                p   += (len + 1);
@@ -1283,7 +1340,7 @@ int name_mangle( char *In, char *Out, char name_type )
                }
        }
 
-       return( name_len(Out) );
+       return result;
 }
 
 /****************************************************************************
@@ -1301,7 +1358,7 @@ static char *name_ptr(char *buf,int ofs)
        } else {
                return(buf+ofs);
        }
-}  
+}
 
 /****************************************************************************
  Extract a netbios name from a buf (into a unix string) return name type.
@@ -1317,7 +1374,7 @@ int name_extract(char *buf,int ofs, fstring name)
                return(0);
        return(name_interpret(p,name));
 }
-  
+
 /****************************************************************************
  Return the total storage length of a mangled name.
 ****************************************************************************/