Removed global_myworkgroup, global_myname, global_myscope. Added liberal
[bbaumbach/samba-autobuild/.git] / source / libsmb / nmblib.c
index 006cb5f5eed4cd953bd12380dadc32f76dba8606..43e32aebbdb1df215b3b3c8df9a11daa45a849ed 100644 (file)
@@ -1,6 +1,5 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 1.9.
+   Unix SMB/CIFS implementation.
    NBT netbios library routines
    Copyright (C) Andrew Tridgell 1994-1998
    
 
 #include "includes.h"
 
-extern int DEBUGLEVEL;
-
 int num_good_sends = 0;
 int num_good_receives = 0;
 
-static struct opcode_names {
+static const struct opcode_names {
        char *nmb_opcode_name;
        int opcode;
 } nmb_header_opcode_names[] = {
-      {"Query",           0 },
-      {"Registration",      5 },
-      {"Release",           6 },
-      {"WACK",              7 },
-      {"Refresh",           8 },
-      {"Refresh(altcode)",  9 },
-      {"Multi-homed Registration", 15 },
-      {0, -1 }
+       {"Query",           0 },
+       {"Registration",      5 },
+       {"Release",           6 },
+       {"WACK",              7 },
+       {"Refresh",           8 },
+       {"Refresh(altcode)",  9 },
+       {"Multi-homed Registration", 15 },
+       {0, -1 }
 };
 
 /****************************************************************************
  * Lookup a nmb opcode name.
  ****************************************************************************/
-static char *lookup_opcode_name( int opcode )
+static const char *lookup_opcode_name( int opcode )
 {
-  struct opcode_names *op_namep;
+  const struct opcode_names *op_namep;
   int i;
 
   for(i = 0; nmb_header_opcode_names[i].nmb_opcode_name != 0; i++) {
@@ -80,7 +77,7 @@ static void debug_nmb_res_rec(struct res_rec *res, char *hdr)
 
       for (j = 0; j < 16; j++)
        {
-         unsigned char x = res->rdata[i+j];
+         uchar x = res->rdata[i+j];
          if (x < 32 || x > 127) x = '.';
          
          if (i+j >= res->rdlength) break;
@@ -92,7 +89,7 @@ static void debug_nmb_res_rec(struct res_rec *res, char *hdr)
       for (j = 0; j < 16; j++)
        {
          if (i+j >= res->rdlength) break;
-         DEBUGADD(4, ("%02X", (unsigned char)res->rdata[i+j]));
+         DEBUGADD(4, ("%02X", (uchar)res->rdata[i+j]));
        }
       
       DEBUGADD(4, ("\n"));
@@ -153,7 +150,7 @@ void debug_nmb_packet(struct packet_struct *p)
 /*******************************************************************
   handle "compressed" name pointers
   ******************************************************************/
-static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length,
+static BOOL handle_name_ptrs(uchar *ubuf,int *offset,int length,
                             BOOL *got_pointer,int *ret)
 {
   int loop_count=0;
@@ -173,33 +170,41 @@ static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length,
   parse a nmb name from "compressed" format to something readable
   return the space taken by the name, or 0 if the name is invalid
   ******************************************************************/
-static int parse_nmb_name(char *inbuf,int offset,int length, struct nmb_name *name)
+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;
+  uchar *ubuf = (uchar *)inbuf;
   int ret = 0;
   BOOL got_pointer=False;
+  int loop_count=0;
+  int offset = ofs;
 
-  if (length - offset < 2) return(0);  
+  if (length - offset < 2)
+    return(0);  
 
   /* handle initial name pointers */
-  if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret)) return(0);
+  if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
+    return(0);
   
   m = ubuf[offset];
 
-  if (!m) return(0);
-  if ((m & 0xC0) || offset+m+2 > length) return(0);
+  if (!m)
+    return(0);
+  if ((m & 0xC0) || offset+m+2 > length)
+    return(0);
 
-  bzero((char *)name,sizeof(*name));
+  memset((char *)name,'\0',sizeof(*name));
 
   /* the "compressed" part */
-  if (!got_pointer) ret += m + 2;
+  if (!got_pointer)
+    ret += m + 2;
   offset++;
-  while (m) {
-    unsigned char c1,c2;
+  while (m > 0) {
+    uchar c1,c2;
     c1 = ubuf[offset++]-'A';
     c2 = ubuf[offset++]-'A';
-    if ((c1 & 0xF0) || (c2 & 0xF0) || (n > sizeof(name->name)-1)) return(0);
+    if ((c1 & 0xF0) || (c2 & 0xF0) || (n > sizeof(name->name)-1))
+      return(0);
     name->name[n++] = (c1<<4) | c2;
     m -= 2;
   }
@@ -208,26 +213,43 @@ static int parse_nmb_name(char *inbuf,int offset,int length, struct nmb_name *na
   if (n==16) {
     /* parse out the name type, 
        its always in the 16th byte of the name */
-    name->name_type = ((unsigned char)name->name[15]) & 0xff;
+    name->name_type = ((uchar)name->name[15]) & 0xff;
   
     /* remove trailing spaces */
     name->name[15] = 0;
     n = 14;
-    while (n && name->name[n]==' ') name->name[n--] = 0;  
+    while (n && name->name[n]==' ')
+      name->name[n--] = 0;  
   }
 
   /* now the domain parts (if any) */
   n = 0;
   while (ubuf[offset]) {
     /* we can have pointers within the domain part as well */
-    if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret)) return(0);
+    if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
+      return(0);
 
     m = ubuf[offset];
-    if (!got_pointer) ret += m+1;
-    if (n) name->scope[n++] = '.';
-    if (m+2+offset>length || n+m+1>sizeof(name->scope)) return(0);
+    /*
+     * Don't allow null domain parts.
+     */
+    if (!m)
+      return(0);
+    if (!got_pointer)
+      ret += m+1;
+    if (n)
+      name->scope[n++] = '.';
+    if (m+2+offset>length || n+m+1>sizeof(name->scope))
+      return(0);
     offset++;
-    while (m--) name->scope[n++] = (char)ubuf[offset++];
+    while (m--)
+      name->scope[n++] = (char)ubuf[offset++];
+
+    /*
+     * Watch for malicious loops.
+     */
+    if (loop_count++ == 10)
+      return 0;
   }
   name->scope[n++] = 0;  
 
@@ -251,7 +273,7 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
 
   if (strcmp(name->name,"*") == 0) {
     /* special case for wildcard name */
-    bzero(buf1,20);
+    memset(buf1,'\0',20);
     buf1[0] = '*';
     buf1[15] = name->name_type;
   } else {
@@ -276,9 +298,9 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
     pstrcpy(&buf[offset+1],name->scope);  
   
     p = &buf[offset+1];
-    while ((p = strchr(p,'.'))) {
-      buf[offset] = PTR_DIFF(p,&buf[offset]);
-      offset += buf[offset];
+    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]);
@@ -287,7 +309,6 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
   return(ret);
 }
 
-
 /*******************************************************************
   useful for debugging messages
   ******************************************************************/
@@ -297,23 +318,15 @@ char *nmb_namestr(struct nmb_name *n)
   static fstring ret[4];
   char *p = ret[i];
 
-  nmb_safe_namestr(n, p, sizeof(fstring));
+  if (!n->scope[0])
+    slprintf(p,sizeof(fstring)-1, "%s<%02x>",n->name,n->name_type);
+  else
+    slprintf(p,sizeof(fstring)-1, "%s<%02x>.%s",n->name,n->name_type,n->scope);
 
   i = (i+1)%4;
   return(p);
 }
 
-/*******************************************************************
-  useful for debugging messages
-  ******************************************************************/
-void nmb_safe_namestr(struct nmb_name *n, char *str, size_t len)
-{
-  if (!n->scope[0])
-    slprintf(str, len-1, "%s<%02x>",n->name,n->name_type);
-  else
-    slprintf(str, len-1, "%s<%02x>.%s",n->name,n->name_type,n->scope);
-}
-
 /*******************************************************************
   allocate and parse some resource records
   ******************************************************************/
@@ -324,13 +337,13 @@ static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length,
   *recs = (struct res_rec *)malloc(sizeof(**recs)*count);
   if (!*recs) return(False);
 
-  bzero(*recs,sizeof(**recs)*count);
+  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);
     (*offset) += l;
     if (!l || (*offset)+10 > length) {
-      free(*recs);
+      SAFE_FREE(*recs);
       return(False);
     }
     (*recs)[i].rr_type = RSVAL(inbuf,(*offset));
@@ -340,7 +353,7 @@ static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length,
     (*offset) += 10;
     if ((*recs)[i].rdlength>sizeof((*recs)[i].rdata) || 
        (*offset)+(*recs)[i].rdlength > length) {
-      free(*recs);
+      SAFE_FREE(*recs);
       return(False);
     }
     memcpy((*recs)[i].rdata,inbuf+(*offset),(*recs)[i].rdlength);
@@ -376,7 +389,7 @@ static int put_res_rec(char *buf,int offset,struct res_rec *recs,int count)
 /*******************************************************************
   put a compressed name pointer record into a packet
   ******************************************************************/
-static int put_compressed_name_ptr(unsigned char *buf,int offset,struct res_rec *rec,int ptr_offset)
+static int put_compressed_name_ptr(uchar *buf,int offset,struct res_rec *rec,int ptr_offset)
 {  
   int ret=0;
   buf[offset] = (0xC0 | ((ptr_offset >> 8) & 0xFF));
@@ -405,7 +418,7 @@ static BOOL parse_dgram(char *inbuf,int length,struct dgram_packet *dgram)
   int offset;
   int flags;
 
-  bzero((char *)dgram,sizeof(*dgram));
+  memset((char *)dgram,'\0',sizeof(*dgram));
 
   if (length < 14) return(False);
 
@@ -447,7 +460,7 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
 {
   int nm_flags,offset;
 
-  bzero((char *)nmb,sizeof(*nmb));
+  memset((char *)nmb,'\0',sizeof(*nmb));
 
   if (length < 12) return(False);
 
@@ -563,13 +576,10 @@ static struct packet_struct *copy_nmb_packet(struct packet_struct *packet)
 
 free_and_exit:
 
-  if(copy_nmb->answers)
-    free((char *)copy_nmb->answers);
-  if(copy_nmb->nsrecs)
-    free((char *)copy_nmb->nsrecs);
-  if(copy_nmb->additional)
-    free((char *)copy_nmb->additional);
-  free((char *)pkt_copy);
+  SAFE_FREE(copy_nmb->answers);
+  SAFE_FREE(copy_nmb->nsrecs);
+  SAFE_FREE(copy_nmb->additional);
+  SAFE_FREE(pkt_copy);
 
   DEBUG(0,("copy_nmb_packet: malloc fail in resource records.\n"));
   return NULL;
@@ -617,9 +627,9 @@ struct packet_struct *copy_packet(struct packet_struct *packet)
   ******************************************************************/
 static void free_nmb_packet(struct nmb_packet *nmb)
 {  
-  if (nmb->answers) free(nmb->answers);
-  if (nmb->nsrecs) free(nmb->nsrecs);
-  if (nmb->additional) free(nmb->additional);
+  SAFE_FREE(nmb->answers);
+  SAFE_FREE(nmb->nsrecs);
+  SAFE_FREE(nmb->additional);
 }
 
 /*******************************************************************
@@ -641,7 +651,48 @@ void free_packet(struct packet_struct *packet)
     free_nmb_packet(&packet->packet.nmb);
   else if (packet->packet_type == DGRAM_PACKET)
     free_dgram_packet(&packet->packet.dgram);
-  free(packet);
+  ZERO_STRUCTPN(packet);
+  SAFE_FREE(packet);
+}
+
+/*******************************************************************
+parse a packet buffer into a packet structure
+  ******************************************************************/
+struct packet_struct *parse_packet(char *buf,int length,
+                                  enum packet_type packet_type)
+{
+       extern struct in_addr lastip;
+       extern int lastport;
+       struct packet_struct *p;
+       BOOL ok=False;
+
+       p = (struct packet_struct *)malloc(sizeof(*p));
+       if (!p) return(NULL);
+
+       p->next = NULL;
+       p->prev = NULL;
+       p->ip = lastip;
+       p->port = lastport;
+       p->locked = False;
+       p->timestamp = time(NULL);
+       p->packet_type = packet_type;
+
+       switch (packet_type) {
+       case NMB_PACKET:
+               ok = parse_nmb(buf,length,&p->packet.nmb);
+               break;
+               
+       case DGRAM_PACKET:
+               ok = parse_dgram(buf,length,&p->packet.dgram);
+               break;
+       }
+
+       if (!ok) {
+               free_packet(p);
+               return NULL;
+       }
+
+       return p;
 }
 
 /*******************************************************************
@@ -650,84 +701,24 @@ void free_packet(struct packet_struct *packet)
   ******************************************************************/
 struct packet_struct *read_packet(int fd,enum packet_type packet_type)
 {
-  extern struct in_addr lastip;
-       struct nmb_state con;
-  extern int lastport;
-  struct packet_struct *packet;
-  char buf[MAX_DGRAM_SIZE];
-  int length;
-  BOOL ok=False;
-  
-       if (packet_type == NMB_SOCK_PACKET || packet_type == DGRAM_SOCK_PACKET)
-       {
-               uint16 trn_id = 0;
-               if (!read_nmb_sock(fd, &con))
-               {
-                       return False;
-               }
-               if (write(fd, &trn_id, sizeof(trn_id)) != sizeof(trn_id))
-               {
-                       return False;
-               }
-       }
+       struct packet_struct *packet;
+       char buf[MAX_DGRAM_SIZE];
+       int length;
        
        length = read_udp_socket(fd,buf,sizeof(buf));
+       if (length < MIN_DGRAM_SIZE) return(NULL);
        
-       dump_data(100, buf, length);
+       packet = parse_packet(buf, length, packet_type);
+       if (!packet) return NULL;
 
-       if (packet_type == NMB_SOCK_PACKET || packet_type == DGRAM_SOCK_PACKET)
-       {
-               uint16 trn_id = 0;
-               if (write(fd, &trn_id, sizeof(trn_id)) != sizeof(trn_id))
-               {
-                       return False;
-               }
-       }
+       packet->fd = fd;
        
-  if (length < MIN_DGRAM_SIZE) return(NULL);
-
-       if (packet_type == NMB_SOCK_PACKET || packet_type == DGRAM_SOCK_PACKET)
-       {
-               lastip = con.ip;
-               lastport = con.port;
-       }
-
-  packet = (struct packet_struct *)malloc(sizeof(*packet));
-  if (!packet) return(NULL);
-
-  packet->next = NULL;
-  packet->prev = NULL;
-  packet->ip = lastip;
-  packet->port = lastport;
-  packet->fd = fd;
-  packet->locked = False;
-  packet->timestamp = time(NULL);
-  packet->packet_type = packet_type;
-  switch (packet_type) 
-    {
-    case NMB_PACKET:
-    case NMB_SOCK_PACKET:
-      ok = parse_nmb(buf,length,&packet->packet.nmb);
-      break;
-
-    case DGRAM_PACKET:
-    case DGRAM_SOCK_PACKET:
-      ok = parse_dgram(buf,length,&packet->packet.dgram);
-      break;
-    }
-  if (!ok) {
-    DEBUG(10,("read_packet: discarding packet id = %d\n", 
-                 packet->packet.nmb.header.name_trn_id));
-    free(packet);
-    return(NULL);
-  }
-
-  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);
+       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);
 }
                                         
 
@@ -736,20 +727,28 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type)
   ******************************************************************/
 static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
 {
-  BOOL ret;
+  BOOL ret = False;
+  int i;
   struct sockaddr_in sock_out;
 
   /* set the address and port */
-  bzero((char *)&sock_out,sizeof(sock_out));
+  memset((char *)&sock_out,'\0',sizeof(sock_out));
   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.
+   */
        
-  ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out,
-               sizeof(sock_out)) >= 0);
+  for (i = 0; i < 5; i++) {
+    ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out, sizeof(sock_out)) >= 0);
+    if (ret || errno != ECONNREFUSED)
+      break;
+  }
 
   if (!ret)
     DEBUG(0,("Packet send failed to %s(%d) ERRNO=%s\n",
@@ -767,16 +766,24 @@ static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
   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 -)------ ]
+
   ******************************************************************/
 static int build_dgram(char *buf,struct packet_struct *p)
 {
   struct dgram_packet *dgram = &p->packet.dgram;
-  unsigned char *ubuf = (unsigned char *)buf;
+  uchar *ubuf = (uchar *)buf;
   int offset=0;
 
   /* put in the header */
   ubuf[0] = dgram->header.msg_type;
-  ubuf[1] = (((unsigned int)dgram->header.flags.node_type)<<2);
+  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);
@@ -796,23 +803,26 @@ static int build_dgram(char *buf,struct packet_struct *p)
   memcpy(ubuf+offset,dgram->data,dgram->datasize);
   offset += dgram->datasize;
 
-  /* automatically set the dgm_length */
-  dgram->header.dgm_length = offset;
+  /* automatically set the dgm_length
+   * NOTE: RFC1002 says the dgm_length does *not*
+   *       include the fourteen-byte header. crh
+   */
+  dgram->header.dgm_length = (offset - 14);
   RSSVAL(ubuf,10,dgram->header.dgm_length); 
 
   return(offset);
 }
 
 /*******************************************************************
-  build a nmb name
- *******************************************************************/
-void make_nmb_name( struct nmb_name *n, const char *name, int type, const char *this_scope )
+ Build a nmb name
+*******************************************************************/
+
+void make_nmb_name( struct nmb_name *n, const char *name, int type)
 {
        memset( (char *)n, '\0', sizeof(struct nmb_name) );
-       StrnCpy( n->name, name, 15 );
-       strupper( n->name );
+       push_ascii(n->name, name, 16, STR_TERMINATE|STR_UPPER);
        n->name_type = (unsigned int)type & 0xFF;
-       StrnCpy( n->scope, this_scope, 63 );
+       StrnCpy( n->scope, global_scope(), 63 );
        strupper( n->scope );
 }
 
@@ -838,7 +848,7 @@ BOOL nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2)
 static int build_nmb(char *buf,struct packet_struct *p)
 {
   struct nmb_packet *nmb = &p->packet.nmb;
-  unsigned char *ubuf = (unsigned char *)buf;
+  uchar *ubuf = (uchar *)buf;
   int offset=0;
 
   /* put in the header */
@@ -901,6 +911,26 @@ static int build_nmb(char *buf,struct packet_struct *p)
 }
 
 
+/*******************************************************************
+linearise a packet
+  ******************************************************************/
+int build_packet(char *buf, struct packet_struct *p)
+{
+       int len = 0;
+
+       switch (p->packet_type) {
+       case NMB_PACKET:
+               len = build_nmb(buf,p);
+               break;
+
+       case DGRAM_PACKET:
+               len = build_dgram(buf,p);
+               break;
+       }
+
+       return len;
+}
+
 /*******************************************************************
   send a packet_struct
   ******************************************************************/
@@ -909,112 +939,113 @@ BOOL send_packet(struct packet_struct *p)
   char buf[1024];
   int len=0;
 
-       DEBUG(100,("send_packet: %d %d\n", p->fd, p->packet_type));
+  memset(buf,'\0',sizeof(buf));
 
-  bzero(buf,sizeof(buf));
-
-  switch (p->packet_type) 
-    {
-    case NMB_PACKET:
-    case NMB_SOCK_PACKET:
-      len = build_nmb(buf,p);
-      debug_nmb_packet(p);
-      break;
-
-    case DGRAM_PACKET:
-    case DGRAM_SOCK_PACKET:
-      len = build_dgram(buf,p);
-      break;
-    }
+  len = build_packet(buf, p);
 
   if (!len) return(False);
 
-  switch (p->packet_type) 
-    {
-    case DGRAM_PACKET:
-    case NMB_PACKET:
-         return(send_udp(p->fd,buf,len,p->ip,p->port));
-      break;
+  return(send_udp(p->fd,buf,len,p->ip,p->port));
+}
 
-    case NMB_SOCK_PACKET:
-    case DGRAM_SOCK_PACKET:
-       {
-               fstring qbuf;
-               struct nmb_state nmb;
-               int qlen;
-               uint16 trn_id;
-               char *q = qbuf + 4;
+/****************************************************************************
+  receive a packet with timeout on a open UDP filedescriptor
+  The timeout is in milliseconds
+  ***************************************************************************/
+struct packet_struct *receive_packet(int fd,enum packet_type type,int t)
+{
+       fd_set fds;
+       struct timeval timeout;
+       int ret;
+
+       FD_ZERO(&fds);
+       FD_SET(fd,&fds);
+       timeout.tv_sec = t/1000;
+       timeout.tv_usec = 1000*(t%1000);
+
+       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));
+               return NULL;
+       }
 
-               nmb.ip = p->ip;
-               nmb.port = p->port;
+       if (ret == 0) /* timeout */
+               return NULL;
 
-               SSVAL(q, 0, 0);
-               q += 2;
-               SSVAL(q, 0, 0);
-               q += 2;
-               memcpy(q, &nmb, sizeof(nmb));
-               q += sizeof(nmb);
+       if (FD_ISSET(fd,&fds)) 
+               return(read_packet(fd,type));
+       
+       return(NULL);
+}
 
-               qlen = PTR_DIFF(q, qbuf);
-               SIVAL(qbuf, 0, qlen);
 
-               dump_data(100, qbuf, qlen);
+/****************************************************************************
+  receive a UDP/137 packet either via UDP or from the unexpected packet
+  queue. The packet must be a reply packet and have the specified trn_id
+  The timeout is in milliseconds
+  ***************************************************************************/
+struct packet_struct *receive_nmb_packet(int fd, int t, int trn_id)
+{
+       struct packet_struct *p;
 
-                 if (write(p->fd,qbuf,qlen) != qlen)
-               {
-                       DEBUG(0,("send_packet: write hdr failed\n"));
-                       return False;
-               }
-               if (read(p->fd, &trn_id, sizeof(trn_id)) != sizeof(trn_id))
-               {
-                       DEBUG(0,("send_packet: 1st ack failed\n"));
-                       return False;
-               }
-               if (write(p->fd,buf,len) != len)
-               {
-                       DEBUG(0,("send_packet: write packet failed\n"));
-                       return False;
-               }
-               if (read(p->fd, &trn_id, sizeof(trn_id)) != sizeof(trn_id))
-               {
-                       DEBUG(0,("send_packet: 2nd ack failed\n"));
-                       return False;
-               }
-               return True;
+       p = receive_packet(fd, NMB_PACKET, t);
+
+       if (p && p->packet.nmb.header.response &&
+           p->packet.nmb.header.name_trn_id == trn_id) {
+               return p;
        }
-    }
+       if (p) free_packet(p);
 
-       return False;
+       /* try the unexpected packet queue */
+       return receive_unexpected(NMB_PACKET, trn_id, NULL);
 }
 
 /****************************************************************************
-  receive a packet with timeout on a open UDP filedescriptor
+  receive a UDP/138 packet either via UDP or from the unexpected packet
+  queue. The packet must be a reply packet and have the specified mailslot name
   The timeout is in milliseconds
   ***************************************************************************/
-struct packet_struct *receive_packet(int fd,enum packet_type type,int t)
+struct packet_struct *receive_dgram_packet(int fd, int t, char *mailslot_name)
+{
+       struct packet_struct *p;
+
+       p = receive_packet(fd, DGRAM_PACKET, t);
+
+       if (p && match_mailslot_name(p, mailslot_name)) {
+               return p;
+       }
+       if (p) free_packet(p);
+
+       /* try the unexpected packet queue */
+       return receive_unexpected(DGRAM_PACKET, 0, mailslot_name);
+}
+
+
+/****************************************************************************
+ see if a datagram has the right mailslot name
+***************************************************************************/
+BOOL match_mailslot_name(struct packet_struct *p, char *mailslot_name)
 {
-  fd_set fds;
-  struct timeval timeout;
+       struct dgram_packet *dgram = &p->packet.dgram;
+       char *buf;
 
-  FD_ZERO(&fds);
-  FD_SET(fd,&fds);
-  timeout.tv_sec = t/1000;
-  timeout.tv_usec = 1000*(t%1000);
+       buf = &dgram->data[0];
+       buf -= 4;
 
-       DEBUG(100,("receive_packet: %d %d\n", fd, type));
-  sys_select(fd+1,&fds,NULL, &timeout);
+       buf = smb_buf(buf);
 
-  if (FD_ISSET(fd,&fds)) 
-    return(read_packet(fd,type));
+       if (memcmp(buf, mailslot_name, strlen(mailslot_name)+1) == 0) {
+               return True;
+       }
 
-  return(NULL);
+       return False;
 }
 
 
 /****************************************************************************
 return the number of bits that match between two 4 character buffers
   ***************************************************************************/
-static int matching_bits(uchar *p1, uchar *p2)
+int matching_quad_bits(uchar *p1, uchar *p2)
 {
        int i, j, ret = 0;
        for (i=0; i<4; i++) {
@@ -1040,7 +1071,7 @@ compare two query reply records
   ***************************************************************************/
 static int name_query_comp(uchar *p1, uchar *p2)
 {
-       return matching_bits(p2+2, sort_ip) - matching_bits(p1+2, sort_ip);
+       return matching_quad_bits(p2+2, sort_ip) - matching_quad_bits(p1+2, sort_ip);
 }
 
 /****************************************************************************
@@ -1056,75 +1087,193 @@ void sort_query_replies(char *data, int n, struct in_addr ip)
        qsort(data, n, 6, QSORT_CAST name_query_comp);
 }
 
-BOOL read_nmb_sock(int c, struct nmb_state *con)
-{
-       fstring buf;
-       char *p = buf;
-       int rl;
-       uint32 len;
-       uint16 version;
-       uint16 command;
 
-       ZERO_STRUCTP(con);
+#define TRUNCATE_NETBIOS_NAME 1
 
-       rl = read(c, &buf, sizeof(len));
+/*******************************************************************
+ 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.
 
-       if (rl < 0)
-       {
-               DEBUG(0,("read_nmb_sock: error\n"));
-               return False;
-       }
-       if (rl != sizeof(len))
+ the netbios name (NOT necessarily null-terminated) is truncated to 15
+ characters.
+
+ ******************************************************************/
+char *dns_to_netbios_name(char *dns_name)
+{
+       static char netbios_name[16];
+       int i;
+       StrnCpy(netbios_name, dns_name, 15);
+       netbios_name[15] = 0;
+       
+#ifdef TRUNCATE_NETBIOS_NAME
+       /* 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 = 15; i >= 0; i--)
        {
-               DEBUG(0,("Unable to read length\n"));
-               dump_data(0, buf, sizeof(len));
-               return False;
+               if (netbios_name[i] == '.')
+               {
+                       netbios_name[i] = 0;
+                       break;
+               }
        }
+#endif /* TRUNCATE_NETBIOS_NAME */
 
-       len = IVAL(buf, 0);
+       return netbios_name;
+}
 
-       if (len > sizeof(buf))
-       {
-               DEBUG(0,("length %d too long\n", len));
-               return False;
-       }
 
-       rl = read(c, buf, len);
+/****************************************************************************
+interpret the weird netbios "name". Return the name type
+****************************************************************************/
+static int name_interpret(char *in,char *out)
+{
+  int ret;
+  int len = (*in++) / 2;
 
-       if (rl < 0)
-       {
-               DEBUG(0,("Unable to read from connection\n"));
-               return False;
-       }
-       
-#ifdef DEBUG_PASSWORD
-       dump_data(100, buf, rl);
+  *out=0;
+
+  if (len > 30 || len<1) return(0);
+
+  while (len--)
+    {
+      if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
+       *out = 0;
+       return(0);
+      }
+      *out = ((in[0]-'A')<<4) + (in[1]-'A');
+      in += 2;
+      out++;
+    }
+  *out = 0;
+  ret = out[-1];
+
+#ifdef NETBIOS_SCOPE
+  /* Handle any scope names */
+  while(*in) 
+    {
+      *out++ = '.'; /* Scope names are separated by periods */
+      len = *(uchar *)in++;
+      StrnCpy(out, in, len);
+      out += len;
+      *out=0;
+      in += len;
+    }
 #endif
-       version = SVAL(p, 0);
-       p += 2;
-       command = SVAL(p, 0);
-       p += 2;
+  return(ret);
+}
 
-       memcpy(con, p, sizeof(*con));
-       p += sizeof(*con);
+/****************************************************************************
+mangle a name into netbios format
 
-       DEBUG(10,("read_nmb_sock: ip %s port: %d\n",
-                  inet_ntoa(con->ip), con->port));
+  Note:  <Out> must be (33 + strlen(scope) + 2) bytes long, at minimum.
+****************************************************************************/
+int name_mangle( char *In, char *Out, char name_type )
+  {
+  int   i;
+  int   c;
+  int   len;
+  char  buf[20];
+  char *p = Out;
+
+  /* Safely copy the input string, In, into buf[]. */
+  (void)memset( buf, 0, 20 );
+  if (strcmp(In,"*") == 0)
+    buf[0] = '*';
+  else
+    (void)slprintf( buf, sizeof(buf) - 1, "%-15.15s%c", In, name_type );
 
-       if (PTR_DIFF(p, buf) != rl)
-       {
-               DEBUG(0,("Buffer size %d %d!\n",
-                       PTR_DIFF(p, buf), rl));
-               return False;
-       }
+  /* Place the length of the first field into the output buffer. */
+  p[0] = 32;
+  p++;
+
+  /* Now convert the name to the rfc1001/1002 format. */
+  for( i = 0; i < 16; i++ )
+    {
+    c = toupper( buf[i] );
+    p[i*2]     = ( (c >> 4) & 0x000F ) + 'A';
+    p[(i*2)+1] = (c & 0x000F) + 'A';
+    }
+  p += 32;
+  p[0] = '\0';
+
+  /* Add the scope string. */
+  for( i = 0, len = 0; NULL != global_scope(); i++, len++ )
+    {
+    switch( (global_scope())[i] )
+      {
+      case '\0':
+        p[0]     = len;
+        if( len > 0 )
+          p[len+1] = 0;
+        return( name_len(Out) );
+      case '.':
+        p[0] = len;
+        p   += (len + 1);
+        len  = -1;
+        break;
+      default:
+        p[len+1] = (global_scope())[i];
+        break;
+      }
+    }
+
+  return( name_len(Out) );
+  } /* name_mangle */
 
-       return True;
-}
 
-int get_nmb_sock(void)
+/****************************************************************************
+find a pointer to a netbios name
+****************************************************************************/
+static char *name_ptr(char *buf,int ofs)
 {
-       fstring path;
-       slprintf(path, sizeof(path)-1, "/tmp/.nmb/agent");
+  uchar c = *(uchar *)(buf+ofs);
+
+  if ((c & 0xC0) == 0xC0)
+    {
+      uint16 l = RSVAL(buf, ofs) & 0x3FFF;
+      DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l));
+      return(buf + l);
+    }
+  else
+    return(buf+ofs);
+}  
 
-       return open_pipe_sock(path);
+/****************************************************************************
+extract a netbios name from a buf
+****************************************************************************/
+int name_extract(char *buf,int ofs,char *name)
+{
+  char *p = name_ptr(buf,ofs);
+  int d = PTR_DIFF(p,buf+ofs);
+  pstrcpy(name,"");
+  if (d < -50 || d > 50) return(0);
+  return(name_interpret(p,name));
 }
+  
+/****************************************************************************
+return the total storage length of a mangled name
+****************************************************************************/
+int name_len(char *s1)
+{
+       /* NOTE: this argument _must_ be unsigned */
+       uchar *s = (uchar *)s1;
+       int len;
+
+       /* If the two high bits of the byte are set, return 2. */
+       if (0xC0 == (*s & 0xC0))
+               return(2);
+
+       /* Add up the length bytes. */
+       for (len = 1; (*s); s += (*s) + 1) {
+               len += *s + 1;
+               SMB_ASSERT(len < 80);
+       }
+
+       return(len);
+} /* name_len */