RFC1002 says we must put compressed name pointers in the following
[samba.git] / source3 / libsmb / nmblib.c
index 456a8218d8b871b71ce47151e7809525872784c9..f2aee12615eb247adb8a2371bedcea32e0752a03 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    NBT netbios library routines
-   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Andrew Tridgell 1994-1998
    
    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
@@ -34,11 +34,13 @@ static struct opcode_names {
        char *nmb_opcode_name;
        int opcode;
 } nmb_header_opcode_names[] = {
-      { "Query",           0 },
+      {"Query",           0 },
       {"Registration",      5 },
       {"Release",           6 },
       {"WACK",              7 },
-      {"refresh",           8 },
+      {"Refresh",           8 },
+      {"Refresh(altcode)",  9 },
+      {"Multi-homed Registration", 15 },
       {0, -1 }
 };
 
@@ -107,8 +109,8 @@ void debug_nmb_packet(struct packet_struct *p)
 {
   struct nmb_packet *nmb = &p->packet.nmb;
   
-  DEBUG(4,("nmb packet from %s header: id=%d opcode=%s(%d) response=%s\n",
-          inet_ntoa(p->ip),
+  DEBUG(4,("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)));
@@ -205,7 +207,7 @@ 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 = name->name[15];
+    name->name_type = ((unsigned char)name->name[15]) & 0xff;
   
     /* remove trailing spaces */
     name->name[15] = 0;
@@ -249,6 +251,7 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
     /* special case for wildcard name */
     bzero(buf1,20);
     buf1[0] = '*';
+    buf1[15] = name->name_type;
   } else {
     sprintf(buf1,"%-15.15s%c",name->name,name->name_type);
   }
@@ -292,9 +295,9 @@ char *namestr(struct nmb_name *n)
   char *p = ret[i];
 
   if (!n->scope[0])
-    sprintf(p,"%s(%x)",n->name,n->name_type);
+    sprintf(p,"%s<%02x>",n->name,n->name_type);
   else
-    sprintf(p,"%s(%x).%s",n->name,n->name_type,n->scope);
+    sprintf(p,"%s<%02x>.%s",n->name,n->name_type,n->scope);
 
   i = (i+1)%4;
   return(p);
@@ -359,6 +362,27 @@ static int put_res_rec(char *buf,int offset,struct res_rec *recs,int count)
   return(ret);
 }
 
+/*******************************************************************
+  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)
+{  
+  int ret=0;
+  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);
+  offset += 10+rec->rdlength;
+  ret += 10+rec->rdlength;
+    
+  return(ret);
+}
+
 /*******************************************************************
   parse a dgram packet. Return False if the packet can't be parsed 
   or is invalid for some reason, True otherwise 
@@ -467,23 +491,145 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
   return(True);
 }
 
+/*******************************************************************
+  'Copy constructor' for an nmb packet
+  ******************************************************************/
+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;
+
+  if(( pkt_copy = (struct packet_struct *)malloc(sizeof(*packet))) == NULL)
+  {
+    DEBUG(0,("copy_nmb_packet: malloc fail.\n"));
+    return NULL;
+  }
+
+  /* Structure copy of entire thing. */
+
+  *pkt_copy = *packet;
+
+  /* Ensure this copy is not locked. */
+  pkt_copy->locked = False;
+
+  /* Ensure this copy has no resource records. */
+  nmb = &packet->packet.nmb;
+  copy_nmb = &pkt_copy->packet.nmb;
+
+  copy_nmb->answers = NULL;
+  copy_nmb->nsrecs = NULL;
+  copy_nmb->additional = NULL;
+
+  /* Now copy any resource records. */
+
+  if (nmb->answers)
+  {
+    if((copy_nmb->answers = (struct res_rec *)
+                  malloc(nmb->header.ancount * sizeof(struct res_rec))) == NULL)
+      goto free_and_exit;
+    memcpy((char *)copy_nmb->answers, (char *)nmb->answers, 
+           nmb->header.ancount * sizeof(struct res_rec));
+  }
+  if (nmb->nsrecs)
+  {
+    if((copy_nmb->nsrecs = (struct res_rec *)
+                  malloc(nmb->header.nscount * sizeof(struct res_rec))) == NULL)
+      goto free_and_exit;
+    memcpy((char *)copy_nmb->nsrecs, (char *)nmb->nsrecs, 
+           nmb->header.nscount * sizeof(struct res_rec));
+  }
+  if (nmb->additional)
+  {
+    if((copy_nmb->additional = (struct res_rec *)
+                  malloc(nmb->header.arcount * sizeof(struct res_rec))) == NULL)
+      goto free_and_exit;
+    memcpy((char *)copy_nmb->additional, (char *)nmb->additional, 
+           nmb->header.arcount * sizeof(struct res_rec));
+  }
+
+  return pkt_copy;
+
+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);
+
+  DEBUG(0,("copy_nmb_packet: malloc fail in resource records.\n"));
+  return NULL;
+}
+
+/*******************************************************************
+  'Copy constructor' for a dgram packet
+  ******************************************************************/
+static struct packet_struct *copy_dgram_packet(struct packet_struct *packet)
+{ 
+  struct packet_struct *pkt_copy;
+
+  if(( pkt_copy = (struct packet_struct *)malloc(sizeof(*packet))) == NULL)
+  {
+    DEBUG(0,("copy_dgram_packet: malloc fail.\n"));
+    return NULL;
+  }
+
+  /* Structure copy of entire thing. */
+
+  *pkt_copy = *packet;
+
+  /* Ensure this copy is not locked. */
+  pkt_copy->locked = False;
+
+  /* There are no additional pointers in a dgram packet,
+     we are finished. */
+  return pkt_copy;
+}
+
+/*******************************************************************
+  'Copy constructor' for a generic 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
   ******************************************************************/
-void free_nmb_packet(struct nmb_packet *nmb)
+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);
 }
 
+/*******************************************************************
+  free up any resources associated with a dgram packet
+  ******************************************************************/
+static void free_dgram_packet(struct dgram_packet *nmb)
+{  
+  /* We have nothing to do for a dgram packet. */
+}
+
 /*******************************************************************
   free up any resources associated with a packet
   ******************************************************************/
 void free_packet(struct packet_struct *packet)
 {  
+  if (packet->locked) 
+    return;
   if (packet->packet_type == NMB_PACKET)
     free_nmb_packet(&packet->packet.nmb);
+  else if (packet->packet_type == DGRAM_PACKET)
+    free_dgram_packet(&packet->packet.dgram);
   free(packet);
 }
 
@@ -511,6 +657,7 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type)
   packet->ip = lastip;
   packet->port = lastport;
   packet->fd = fd;
+  packet->locked = False;
   packet->timestamp = time(NULL);
   packet->packet_type = packet_type;
   switch (packet_type) 
@@ -616,12 +763,22 @@ static int build_dgram(char *buf,struct packet_struct *p)
   ******************************************************************/
 void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope)
 {
-  strcpy(n->name,name);
+  StrnCpy(n->name,name,15);
   strupper(n->name);
-  n->name_type = type;
-  strcpy(n->scope,this_scope);
+  n->name_type = (unsigned int)type & 0xFF;
+  StrnCpy(n->scope,this_scope,63);
 }
 
+/*******************************************************************
+  Compare two nmb names
+  ******************************************************************/
+
+BOOL nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2)
+{
+  return ((n1->name_type == n2->name_type) &&
+         strequal(n1->name ,n2->name ) &&
+         strequal(n1->scope,n2->scope));
+}
 
 /*******************************************************************
   build a nmb packet ready for sending
@@ -672,10 +829,27 @@ static int build_nmb(char *buf,struct packet_struct *p)
     offset += put_res_rec((char *)ubuf,offset,nmb->nsrecs,
                          nmb->header.nscount);
 
-  if (nmb->header.arcount)
+  /*
+   * The spec says we must put compressed name pointers
+   * in the following outgoing packets :
+   * NAME_REGISTRATION_REQUEST, NAME_REFRESH_REQUEST,
+   * NAME_RELEASE_REQUEST.
+   */
+
+  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);
+
+  } else if (nmb->header.arcount) {
     offset += put_res_rec((char *)ubuf,offset,nmb->additional,
                          nmb->header.arcount);  
-
+  }
   return(offset);
 }
 
@@ -694,6 +868,7 @@ BOOL send_packet(struct packet_struct *p)
     {
     case NMB_PACKET:
       len = build_nmb(buf,p);
+      debug_nmb_packet(p);
       break;
 
     case DGRAM_PACKET: