Merge from HEAD - make Samba compile with -Wwrite-strings without additional
[vlendec/samba-autobuild/.git] / source3 / nmbd / nmbd_packets.c
index 142268b0b01bfa93c0d313bc3852ce42f5817a19..d83cd10d0cbb6239cb4ae6db403fab76b9ef82c7 100644 (file)
@@ -1,6 +1,5 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 1.9.
+   Unix SMB/CIFS implementation.
    NBT netbios routines and daemon - version 2
    Copyright (C) Andrew Tridgell 1994-1998
    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
@@ -28,8 +27,6 @@ extern int ClientNMB;
 extern int ClientDGRAM;
 extern int global_nmb_port;
 
-extern int DEBUGLEVEL;
-
 extern int num_response_packets;
 
 extern struct in_addr loopback_ip;
@@ -240,40 +237,44 @@ static BOOL create_and_init_additional_record(struct packet_struct *packet,
                                                      uint16 nb_flags,
                                                      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"));
-    return False;
-  }
-
-  memset((char *)nmb->additional,'\0',sizeof(struct res_rec));
-
-  nmb->additional->rr_name  = nmb->question.question_name;
-  nmb->additional->rr_type  = RR_TYPE_NB;
-  nmb->additional->rr_class = RR_CLASS_IN;
-
-  /* See RFC 1002, sections 5.1.1.1, 5.1.1.2 and 5.1.1.3 */
-  if (nmb->header.nm_flags.bcast)
-    nmb->additional->ttl = PERMANENT_TTL;
-  else
-    nmb->additional->ttl = lp_max_ttl();
-
-  nmb->additional->rdlength = 6;
-
-  set_nb_flags(nmb->additional->rdata,nb_flags);
-
-  /* Set the address for the name we are registering. */
-  putip(&nmb->additional->rdata[2], register_ip);
-
-  /* Ensure that we send out the file descriptor to give us the
-     the specific source address we are registering as our
-     IP source address. */
-
-  packet->fd = find_subnet_fd_for_address( *register_ip );
-
-  return True;
+       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"));
+               return False;
+       }
+
+       memset((char *)nmb->additional,'\0',sizeof(struct res_rec));
+
+       nmb->additional->rr_name  = nmb->question.question_name;
+       nmb->additional->rr_type  = RR_TYPE_NB;
+       nmb->additional->rr_class = RR_CLASS_IN;
+       
+       /* See RFC 1002, sections 5.1.1.1, 5.1.1.2 and 5.1.1.3 */
+       if (nmb->header.nm_flags.bcast)
+               nmb->additional->ttl = PERMANENT_TTL;
+       else
+               nmb->additional->ttl = lp_max_ttl();
+       
+       nmb->additional->rdlength = 6;
+       
+       set_nb_flags(nmb->additional->rdata,nb_flags);
+       
+       /* Set the address for the name we are registering. */
+       putip(&nmb->additional->rdata[2], register_ip);
+       
+       /* 
+          it turns out that Jeremys code was correct, we are supposed
+          to send registrations from the IP we are registering. The
+          trick is what to do on timeouts! When we send on a
+          non-routable IP then the reply will timeout, and we should
+          treat this as success, not failure. That means we go into
+          our standard refresh cycle for that name which copes nicely
+          with disconnected networks.
+       */
+       packet->fd = find_subnet_fd_for_address(*register_ip);
+
+       return True;
 }
 
 /***************************************************************************
@@ -348,28 +349,28 @@ 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,
-                                    uint16 nb_flags, struct in_addr *register_ip)
+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;
-  fstring second_ip_buf;
-
-  fstrcpy(second_ip_buf, inet_ntoa(packet->ip));
-
-  nmb->header.opcode = NMB_NAME_MULTIHOMED_REG_OPCODE;
-  nmb->header.arcount = 1;
+       struct nmb_packet *nmb = &packet->packet.nmb;
+       fstring second_ip_buf;
 
-  nmb->header.nm_flags.recursion_desired = True;
+       fstrcpy(second_ip_buf, inet_ntoa(packet->ip));
 
-  if(create_and_init_additional_record(packet, nb_flags, register_ip) == False)
-    return False;
+       nmb->header.opcode = NMB_NAME_MULTIHOMED_REG_OPCODE;
+       nmb->header.arcount = 1;
 
-  DEBUG(4,("initiate_multihomed_name_register_packet: sending registration \
+       nmb->header.nm_flags.recursion_desired = True;
+       
+       if(create_and_init_additional_record(packet, nb_flags, register_ip) == False)
+               return False;
+       
+       DEBUG(4,("initiate_multihomed_name_register_packet: sending registration \
 for name %s IP %s (bcast=%s) to IP %s\n",
-          nmb_namestr(&nmb->additional->rr_name), inet_ntoa(*register_ip),
-           BOOLSTR(nmb->header.nm_flags.bcast), second_ip_buf ));
+                nmb_namestr(&nmb->additional->rr_name), inet_ntoa(*register_ip),
+                BOOLSTR(nmb->header.nm_flags.bcast), second_ip_buf ));
 
-  return send_netbios_packet( packet );
+       return send_netbios_packet( packet );
 } 
 
 /***************************************************************************
@@ -513,65 +514,123 @@ struct response_record *queue_register_name( struct subnet_record *subrec,
   return rrec;
 }
 
+
+/****************************************************************************
+ Queue a refresh name packet to the broadcast address of a subnet.
+****************************************************************************/
+void queue_wins_refresh(struct nmb_name *nmbname,
+                       response_function resp_fn,
+                       timeout_response_function timeout_fn,
+                       uint16 nb_flags,
+                       struct in_addr refresh_ip,
+                       const char *tag)
+{
+       struct packet_struct *p;
+       struct response_record *rrec;
+       struct in_addr wins_ip;
+       struct userdata_struct *userdata;
+       fstring ip_str;
+
+       wins_ip = wins_srv_ip_tag(tag, refresh_ip);
+
+       if ((p = create_and_init_netbios_packet(nmbname, False, False, wins_ip)) == NULL) {
+               return;
+       }
+
+       if (!initiate_name_refresh_packet(p, nb_flags, &refresh_ip)) {
+               p->locked = False;
+               free_packet(p);
+               return;
+       }
+
+       fstrcpy(ip_str, inet_ntoa(refresh_ip));
+
+       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);
+       if (!userdata) {
+               DEBUG(0,("Failed to allocate userdata structure!\n"));
+               return;
+       }
+       ZERO_STRUCTP(userdata);
+       userdata->userdata_len = strlen(tag) + 1;
+       strlcpy(userdata->data, tag, userdata->userdata_len);   
+
+       if ((rrec = make_response_record(unicast_subnet,
+                                        p,
+                                        resp_fn, timeout_fn,
+                                        NULL,
+                                        NULL,
+                                        userdata)) == NULL) {
+               p->locked = False;
+               free_packet(p);
+               return;
+       }
+
+       free(userdata);
+
+       /* we don't want to repeat refresh packets */
+       rrec->repeat_count = 0;
+}
+
+
 /****************************************************************************
- Queue a multihomed register name packet to the broadcast address of a subnet.
+ Queue a multihomed register name packet to a given WINS server IP
 ****************************************************************************/
 
 struct response_record *queue_register_multihomed_name( struct subnet_record *subrec,
-                          response_function resp_fn,
-                          timeout_response_function timeout_fn,
-                          register_name_success_function success_fn,
-                          register_name_fail_function fail_fn,
-                          struct userdata_struct *userdata,
-                          struct nmb_name *nmbname,
-                          uint16 nb_flags,
-                          struct in_addr register_ip)
+                                                       response_function resp_fn,
+                                                       timeout_response_function timeout_fn,
+                                                       register_name_success_function success_fn,
+                                                       register_name_fail_function fail_fn,
+                                                       struct userdata_struct *userdata,
+                                                       struct nmb_name *nmbname,
+                                                       uint16 nb_flags,
+                                                       struct in_addr register_ip,
+                                                       struct in_addr wins_ip)
 {
-  struct packet_struct *p;
-  struct response_record *rrec;
-  BOOL ret;
-     
-  /* Sanity check. */
-  if(subrec != unicast_subnet)
-  {
-    DEBUG(0,("queue_register_multihomed_name: should only be done on \
+       struct packet_struct *p;
+       struct response_record *rrec;
+       BOOL ret;
+       
+       /* Sanity check. */
+       if(subrec != unicast_subnet) {
+               DEBUG(0,("queue_register_multihomed_name: should only be done on \
 unicast subnet. subnet is %s\n.", subrec->subnet_name ));
-    return NULL;
-  }
+               return NULL;
+       }
 
-  if(assert_check_subnet(subrec))
-    return NULL;
+       if(assert_check_subnet(subrec))
+               return NULL;
      
-  if(( p = create_and_init_netbios_packet(nmbname, False, True,
-                                         subrec->bcast_ip)) == NULL)
-    return NULL;
-
-  if (nb_flags & NB_GROUP)
-    ret = initiate_name_register_packet( p, nb_flags, &register_ip);
-  else
-    ret = initiate_multihomed_name_register_packet( p, nb_flags, &register_ip);
-
-  if(ret == False)
-  {  
-    p->locked = False;
-    free_packet(p);
-    return NULL;
-  }  
-  
-  if((rrec = make_response_record(subrec,    /* subnet record. */
-                p,                     /* packet we sent. */
-                resp_fn,               /* function to call on response. */
-                timeout_fn,            /* function to call on timeout. */
-                (success_function)success_fn,            /* function to call on operation success. */
-                (fail_function)fail_fn,               /* function to call on operation fail. */
-                userdata)) == NULL)
-  {  
-    p->locked = False;
-    free_packet(p);
-    return NULL;
-  }  
+       if ((p = create_and_init_netbios_packet(nmbname, False, True, wins_ip)) == NULL)
+               return NULL;
+
+       if (nb_flags & NB_GROUP)
+               ret = initiate_name_register_packet( p, nb_flags, &register_ip);
+       else
+               ret = initiate_multihomed_name_register_packet(p, nb_flags, &register_ip);
+
+       if (ret == False) {  
+               p->locked = False;
+               free_packet(p);
+               return NULL;
+       }  
   
-  return rrec;
+       if ((rrec = make_response_record(subrec,    /* subnet record. */
+                                        p,                     /* packet we sent. */
+                                        resp_fn,               /* function to call on response. */
+                                        timeout_fn,            /* function to call on timeout. */
+                                        (success_function)success_fn, /* function to call on operation success. */
+                                        (fail_function)fail_fn,       /* function to call on operation fail. */
+                                        userdata)) == NULL) {  
+               p->locked = False;
+               free_packet(p);
+               return NULL;
+       }  
+       
+       return rrec;
 }
 
 /****************************************************************************
@@ -579,14 +638,15 @@ unicast subnet. subnet is %s\n.", subrec->subnet_name ));
 ****************************************************************************/
 
 struct response_record *queue_release_name( struct subnet_record *subrec,
-                          response_function resp_fn,
-                          timeout_response_function timeout_fn,
-                          release_name_success_function success_fn,
-                          release_name_fail_function fail_fn,
-                          struct userdata_struct *userdata,
-                          struct nmb_name *nmbname,
-                          uint16 nb_flags,
-                          struct in_addr release_ip)
+                                           response_function resp_fn,
+                                           timeout_response_function timeout_fn,
+                                           release_name_success_function success_fn,
+                                           release_name_fail_function fail_fn,
+                                           struct userdata_struct *userdata,
+                                           struct nmb_name *nmbname,
+                                           uint16 nb_flags,
+                                           struct in_addr release_ip,
+                                           struct in_addr dest_ip)
 {
   struct packet_struct *p;
   struct response_record *rrec;
@@ -595,7 +655,7 @@ struct response_record *queue_release_name( struct subnet_record *subrec,
     return NULL;
 
   if ((p = create_and_init_netbios_packet(nmbname, (subrec != unicast_subnet), False,
-                     subrec->bcast_ip)) == NULL)
+                                         dest_ip)) == NULL)
     return NULL;
 
   if(initiate_name_release_packet( p, nb_flags, &release_ip) == False)
@@ -631,52 +691,6 @@ struct response_record *queue_release_name( struct subnet_record *subrec,
   return rrec;
 }
 
-/****************************************************************************
- Queue a refresh name packet to the broadcast address of a subnet.
-****************************************************************************/
-
-struct response_record *queue_refresh_name( struct subnet_record *subrec,
-                          response_function resp_fn,
-                          timeout_response_function timeout_fn,
-                          refresh_name_success_function success_fn,
-                          refresh_name_fail_function fail_fn,
-                          struct userdata_struct *userdata,
-                          struct name_record *namerec,
-                          struct in_addr refresh_ip)
-{
-  struct packet_struct *p;
-  struct response_record *rrec;
-
-  if(assert_check_subnet(subrec))
-    return NULL;
-
-  if(( p = create_and_init_netbios_packet(&namerec->name, (subrec != unicast_subnet), False,
-                     subrec->bcast_ip)) == NULL)
-    return NULL;
-
-  if( !initiate_name_refresh_packet( p, namerec->data.nb_flags, &refresh_ip ) )
-  {
-    p->locked = False;
-    free_packet(p);
-    return NULL;
-  }
-
-  if((rrec = make_response_record(subrec,           /* subnet record. */
-                  p,                     /* packet we sent. */
-                  resp_fn,               /* function to call on response. */
-                  timeout_fn,            /* function to call on timeout. */
-                  (success_function)success_fn,            /* function to call on operation success. */
-                  (fail_function)fail_fn,               /* function to call on operation fail. */
-                  userdata)) == NULL)
-  {
-    p->locked = False;
-    free_packet(p);
-    return NULL;
-  }
-  
-  return rrec;
-}
-
 /****************************************************************************
  Queue a query name packet to the broadcast address of a subnet.
 ****************************************************************************/
@@ -691,14 +705,33 @@ struct response_record *queue_query_name( struct subnet_record *subrec,
 {
   struct packet_struct *p;
   struct response_record *rrec;
+  struct in_addr to_ip;
 
   if(assert_check_subnet(subrec))
     return NULL;
 
+  to_ip = subrec->bcast_ip;
+  
+  /* 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)) {
+         /* 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
+          * be used when we get here). For now we just query the first
+          * active wins server on the first tag. */
+         char **tags = wins_srv_tags();
+         if (!tags) {
+                 return NULL;
+         }
+         to_ip = wins_srv_ip_tag(tags[0], to_ip);
+         wins_srv_tags_free(tags);
+  }
+
   if(( p = create_and_init_netbios_packet(nmbname, 
                                          (subrec != unicast_subnet), 
                                          (subrec == unicast_subnet), 
-                                         subrec->bcast_ip)) == NULL)
+                                         to_ip)) == NULL)
     return NULL;
 
   if(lp_bind_interfaces_only()) {
@@ -854,7 +887,7 @@ void reply_netbios_packet(struct packet_struct *orig_packet,
   struct res_rec answers;
   struct nmb_packet *orig_nmb = &orig_packet->packet.nmb;
   BOOL loopback_this_packet = False;
-  char *packet_type = "unknown";
+  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))
@@ -1047,15 +1080,14 @@ static void process_browse_packet(struct packet_struct *p, char *buf,int len)
   struct dgram_packet *dgram = &p->packet.dgram;
   int command = CVAL(buf,0);
   struct subnet_record *subrec = find_subnet_for_dgram_browse_packet(p);
-  extern pstring global_scope;
 
   /* Drop the packet if it's a different NetBIOS scope, or
      the source is from one of our names. */
 
-  if (!strequal(dgram->dest_name.scope, global_scope))
+  if (!strequal(dgram->dest_name.scope, global_scope()))
   {
     DEBUG(7,("process_browse_packet: Discarding datagram from IP %s. Scope (%s) \
-mismatch with our scope (%s).\n", inet_ntoa(p->ip), dgram->dest_name.scope, global_scope));
+mismatch with our scope (%s).\n", inet_ntoa(p->ip), dgram->dest_name.scope, global_scope()));
     return;
   }
 
@@ -1160,15 +1192,14 @@ static void process_lanman_packet(struct packet_struct *p, char *buf,int len)
   struct dgram_packet *dgram = &p->packet.dgram;
   int command = SVAL(buf,0);
   struct subnet_record *subrec = find_subnet_for_dgram_browse_packet(p);
-  extern pstring global_scope;
 
   /* Drop the packet if it's a different NetBIOS scope, or
      the source is from one of our names. */
 
-  if (!strequal(dgram->dest_name.scope, global_scope))
+  if (!strequal(dgram->dest_name.scope, global_scope()))
   {
     DEBUG(7,("process_lanman_packet: Discarding datagram from IP %s. Scope (%s) \
-mismatch with our scope (%s).\n", inet_ntoa(p->ip), dgram->dest_name.scope, global_scope));
+mismatch with our scope (%s).\n", inet_ntoa(p->ip), dgram->dest_name.scope, global_scope()));
     return;
   }
 
@@ -1265,14 +1296,21 @@ an error packet of type %x\n",
   len = SVAL(buf,smb_vwv11);
   buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
 
+  if (len <= 0)
+    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;
+  }
+
   DEBUG(4,("process_dgram: datagram from %s to %s IP %s for %s of type %d len=%d\n",
           nmb_namestr(&dgram->source_name),nmb_namestr(&dgram->dest_name),
           inet_ntoa(p->ip), smb_buf(buf),CVAL(buf2,0),len));
 
  
-  if (len <= 0)
-    return;
-
   /* Datagram packet received for the browser mailslot */
   if (strequal(smb_buf(buf),BROWSE_MAILSLOT))
   {
@@ -1649,7 +1687,7 @@ void retransmit_or_expire_response_records(time_t t)
 to IP %s on subnet %s\n", rrec->response_id, inet_ntoa(rrec->packet->ip), 
                           subrec->subnet_name));
           }
-          rrec->repeat_time += rrec->repeat_interval;
+          rrec->repeat_time = t + rrec->repeat_interval;
           rrec->repeat_count--;
         }
         else
@@ -1751,8 +1789,8 @@ only use %d.\n", (count*2) + 2, FD_SETSIZE));
 
   *listen_number = (count*2) + 2;
 
-  if (*ppset) free(*ppset);
-  if (*psock_array) free(*psock_array);
+  SAFE_FREE(*ppset);
+  SAFE_FREE(*psock_array);
 
   *ppset = pset;
   *psock_array = sock_array;
@@ -1813,7 +1851,7 @@ BOOL listen_for_packets(BOOL run_election)
 
   BlockSignals(False, SIGTERM);
 
-  selrtn = sys_select(FD_SETSIZE,&fds,&timeout);
+  selrtn = sys_select(FD_SETSIZE,&fds,NULL,NULL,&timeout);
 
   /* We can only take signals when we are in the select - block them again here. */
 
@@ -1845,8 +1883,9 @@ BOOL listen_for_packets(BOOL run_election)
                                                   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) {
-                                         DEBUG(7,("discarding own packet from %s:%d\n",
+                                             ismyip(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));          
                                          free_packet(packet);
                                  } else {
@@ -1872,7 +1911,7 @@ BOOL listen_for_packets(BOOL run_election)
                                          free_packet(packet);
                                  } else if ((ip_equal(loopback_ip, packet->ip) || 
                                              ismyip(packet->ip)) && packet->port == DGRAM_PORT) {
-                                         DEBUG(7,("discarding own packet from %s:%d\n",
+                                         DEBUG(7,("discarding own dgram packet from %s:%d\n",
                                                   inet_ntoa(packet->ip),packet->port));          
                                          free_packet(packet);
                                  } else {
@@ -1890,9 +1929,9 @@ BOOL listen_for_packets(BOOL run_election)
 /****************************************************************************
   Construct and send a netbios DGRAM.
 **************************************************************************/
-BOOL send_mailslot(BOOL unique, char *mailslot,char *buf,int len,
-                   char *srcname, int src_type,
-                   char *dstname, int dest_type,
+BOOL send_mailslot(BOOL unique, const char *mailslot,char *buf,int 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)
 {
@@ -1928,10 +1967,10 @@ BOOL send_mailslot(BOOL unique, char *mailslot,char *buf,int len,
   /* Setup the smb part. */
   ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
   memcpy(tmp,ptr,4);
-  set_message(ptr,17,17 + len,True);
+  set_message(ptr,17,23 + len,True);
   memcpy(ptr,tmp,4);
 
-  CVAL(ptr,smb_com) = SMBtrans;
+  SCVAL(ptr,smb_com,SMBtrans);
   SSVAL(ptr,smb_vwv1,len);
   SSVAL(ptr,smb_vwv11,len);
   SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));