client.c: Changed shadowed variable.
[kai/samba.git] / source3 / lib / util.c
index ce0b8bc7682696a8f1aedefeb6bb3f10c4ce6270..611794c4a8603ca73b3a4c078b0408214cd749ba 100644 (file)
@@ -807,7 +807,7 @@ char *attrib_string(int mode)
 /*******************************************************************
   case insensitive string compararison
 ********************************************************************/
-int StrCaseCmp(const char *s, const char *t)
+int StrCaseCmp(char *s, char *t)
 {
   /* compare until we run out of string, either t or s, or find a difference */
   /* We *must* use toupper rather than tolower here due to the
@@ -871,7 +871,7 @@ int StrCaseCmp(const char *s, const char *t)
 /*******************************************************************
   case insensitive string compararison, length limited
 ********************************************************************/
-int StrnCaseCmp(const char *s, const char *t, int n)
+int StrnCaseCmp(char *s, char *t, int n)
 {
   /* compare until we run out of string, either t or s, or chars */
   /* We *must* use toupper rather than tolower here due to the
@@ -945,7 +945,7 @@ int StrnCaseCmp(const char *s, const char *t, int n)
 /*******************************************************************
   compare 2 strings 
 ********************************************************************/
-BOOL strequal(const char *s1, const char *s2)
+BOOL strequal(char *s1, char *s2)
 {
   if (s1 == s2) return(True);
   if (!s1 || !s2) return(False);
@@ -956,7 +956,7 @@ BOOL strequal(const char *s1, const char *s2)
 /*******************************************************************
   compare 2 strings up to and including the nth char.
   ******************************************************************/
-BOOL strnequal(const char *s1,const char *s2,int n)
+BOOL strnequal(char *s1,char *s2,int n)
 {
   if (s1 == s2) return(True);
   if (!s1 || !s2 || !n) return(False);
@@ -1117,7 +1117,7 @@ void unix_format(char *fname)
 
   if (*fname == '/')
     {
-      strcpy(namecopy,fname);
+      pstrcpy(namecopy,fname);
       strcpy(fname,".");
       strcat(fname,namecopy);
     }  
@@ -1328,7 +1328,7 @@ void dos_clean_name(char *s)
       pstring s1;
 
       *p = 0;
-      strcpy(s1,p+3);
+      pstrcpy(s1,p+3);
 
       if ((p=strrchr(s,'\\')) != NULL)
        *p = 0;
@@ -1366,7 +1366,7 @@ void unix_clean_name(char *s)
       pstring s1;
 
       *p = 0;
-      strcpy(s1,p+3);
+      pstrcpy(s1,p+3);
 
       if ((p=strrchr(s,'/')) != NULL)
        *p = 0;
@@ -1393,7 +1393,7 @@ int ChDir(char *path)
   DEBUG(3,("chdir to %s\n",path));
   res = sys_chdir(path);
   if (!res)
-    strcpy(LastDir,path);
+    pstrcpy(LastDir,path);
   return(res);
 }
 
@@ -1488,7 +1488,7 @@ char *GetWd(char *str)
 
   if (!sys_getwd(s))
     {
-      DEBUG(0,("Getwd failed, errno %d\n",errno));
+      DEBUG(0,("Getwd failed, errno %s\n",strerror(errno)));
       return (NULL);
     }
 
@@ -1553,7 +1553,7 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
   /* remove any double slashes */
   string_sub(s,"//","/");
 
-  strcpy(basename,s);
+  pstrcpy(basename,s);
   p = strrchr(basename,'/');
 
   if (!p)
@@ -1623,12 +1623,12 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
     if (relative)
       {
        if (newname[l] == '/')
-         strcpy(s,newname + l + 1);
+         pstrcpy(s,newname + l + 1);
        else
-         strcpy(s,newname+l);
+         pstrcpy(s,newname+l);
       }
     else
-      strcpy(s,newname);
+      pstrcpy(s,newname);
   }
 
   ChDir(wd);
@@ -1652,10 +1652,10 @@ static void expand_one(char *Mask,int len)
       int lfill = (len+1) - strlen(Mask);
       int l1= (p1 - Mask);
       pstring tmp;
-      strcpy(tmp,Mask);  
+      pstrcpy(tmp,Mask);  
       memset(tmp+l1,'?',lfill);
-      strcpy(tmp + l1 + lfill,Mask + l1 + 1);  
-      strcpy(Mask,tmp);      
+      pstrcpy(tmp + l1 + lfill,Mask + l1 + 1); 
+      pstrcpy(Mask,tmp);      
     }
 }
 
@@ -1679,20 +1679,20 @@ void expand_mask(char *Mask,BOOL doext)
 
   filename_dos(Mask,filepart);
 
-  strcpy(mbeg,filepart);
+  pstrcpy(mbeg,filepart);
   if ((p1 = strchr(mbeg,'.')) != NULL)
     {
       hasdot = True;
       *p1 = 0;
       p1++;
-      strcpy(mext,p1);
+      pstrcpy(mext,p1);
     }
   else
     {
       strcpy(mext,"");
       if (strlen(mbeg) > 8)
        {
-         strcpy(mext,mbeg + 8);
+         pstrcpy(mext,mbeg + 8);
          mbeg[8] = 0;
        }
     }
@@ -1710,7 +1710,7 @@ void expand_mask(char *Mask,BOOL doext)
   if (*mext)
     expand_one(mext,3);
 
-  strcpy(Mask,dirpart);
+  pstrcpy(Mask,dirpart);
   if (*dirpart || absolute) strcat(Mask,"\\");
   strcat(Mask,mbeg);
   strcat(Mask,".");
@@ -1839,7 +1839,7 @@ void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode
   char *p;
   pstring mask2;
 
-  strcpy(mask2,mask);
+  pstrcpy(mask2,mask);
 
   if ((mode & aDIR) != 0)
     size = 0;
@@ -1951,7 +1951,7 @@ int read_udp_socket(int fd,char *buf,int len)
   bzero((char *)&lastip,sizeof(lastip));
   ret = recvfrom(fd,buf,len,0,&sock,&socklen);
   if (ret <= 0) {
-    DEBUG(2,("read socket failed. ERRNO=%d\n",errno));
+    DEBUG(2,("read socket failed. ERRNO=%s\n",strerror(errno)));
     return(0);
   }
 
@@ -2270,10 +2270,11 @@ int read_smb_length(int fd,char *inbuf,int timeout)
 
 
 /****************************************************************************
-  read an smb from a fd and return it's length
+  read an smb from a fd. Note that the buffer *MUST* be of size
+  BUFFER_SIZE+SAFETY_MARGIN.
 The timeout is in milli seconds
 ****************************************************************************/
-BOOL receive_smb(int fd,char *buffer,int timeout)
+BOOL receive_smb(int fd,char *buffer, int timeout)
 {
   int len,ret;
 
@@ -2300,6 +2301,202 @@ BOOL receive_smb(int fd,char *buffer,int timeout)
   return(True);
 }
 
+/****************************************************************************
+  read a message from a udp fd.
+The timeout is in milli seconds
+****************************************************************************/
+BOOL receive_local_message(int fd, char *buffer, int buffer_len, int timeout)
+{
+  struct sockaddr_in from;
+  int fromlen = sizeof(from);
+  int32 msg_len = 0;
+
+  if(timeout != 0)
+  {
+    struct timeval to;
+    fd_set fds;
+    int selrtn;
+
+    FD_ZERO(&fds);
+    FD_SET(fd,&fds);
+
+    to.tv_sec = timeout / 1000;
+    to.tv_usec = (timeout % 1000) * 1000;
+
+    selrtn = sys_select(&fds,&to);
+
+    /* Check if error */
+    if(selrtn == -1) 
+    {
+      /* something is wrong. Maybe the socket is dead? */
+      smb_read_error = READ_ERROR;
+      return False;
+    } 
+    
+    /* Did we timeout ? */
+    if (selrtn == 0) 
+    {
+      smb_read_error = READ_TIMEOUT;
+      return False;
+    }
+  }
+
+  /*
+   * Read a loopback udp message.
+   */
+  msg_len = recvfrom(fd, &buffer[UDP_CMD_HEADER_LEN], 
+                     buffer_len - UDP_CMD_HEADER_LEN, 0,
+                     (struct sockaddr *)&from, &fromlen);
+
+  if(msg_len < 0)
+  {
+    DEBUG(0,("receive_local_message. Error in recvfrom. (%s).\n",strerror(errno)));
+    return False;
+  }
+
+  /* Validate message length. */
+  if(msg_len > (buffer_len - UDP_CMD_HEADER_LEN))
+  {
+    DEBUG(0,("receive_local_message: invalid msg_len (%d) max can be %d\n",
+              msg_len, 
+              buffer_len  - UDP_CMD_HEADER_LEN));
+    return False;
+  }
+
+  /* Validate message from address (must be localhost). */
+  if(from.sin_addr.s_addr != htonl(INADDR_LOOPBACK))
+  {
+    DEBUG(0,("receive_local_message: invalid 'from' address \
+(was %x should be 127.0.0.1\n", from.sin_addr.s_addr));
+   return False;
+  }
+
+  /* Setup the message header */
+  SIVAL(buffer,UDP_CMD_LEN_OFFSET,msg_len);
+  SSVAL(buffer,UDP_CMD_PORT_OFFSET,ntohs(from.sin_port));
+
+  return True;
+}
+
+/****************************************************************************
+ structure to hold a linked list of local udp messages.
+ for processing.
+****************************************************************************/
+
+typedef struct _udp_message_list {
+   struct _udp_message_list *msg_next;
+   char *msg_buf;
+   int msg_len;
+} udp_message_list;
+
+static udp_message_list *udp_msg_head = NULL;
+
+/****************************************************************************
+ Function to push a linked list of local udp messages ready
+ for processing.
+****************************************************************************/
+BOOL push_local_message(char *buf, int msg_len)
+{
+  udp_message_list *msg = (udp_message_list *)malloc(sizeof(udp_message_list));
+
+  if(msg == NULL)
+  {
+    DEBUG(0,("push_local_message: malloc fail (1)\n"));
+    return False;
+  }
+
+  msg->msg_buf = (char *)malloc(msg_len);
+  if(msg->msg_buf == NULL)
+  {
+    DEBUG(0,("push_local_message: malloc fail (2)\n"));
+    free((char *)msg);
+    return False;
+  }
+
+  memcpy(msg->msg_buf, buf, msg_len);
+  msg->msg_len = msg_len;
+
+  msg->msg_next = udp_msg_head;
+  udp_msg_head = msg;
+
+  return True;
+}
+
+/****************************************************************************
+  Do a select on an two fd's - with timeout. 
+
+  If a local udp message has been pushed onto the
+  queue (this can only happen during oplock break
+  processing) return this first.
+
+  If the first smbfd is ready then read an smb from it.
+  if the second (loopback UDP) fd is ready then read a message
+  from it and setup the buffer header to identify the length
+  and from address.
+  Returns False on timeout or error.
+  Else returns True.
+
+The timeout is in milli seconds
+****************************************************************************/
+BOOL receive_message_or_smb(int smbfd, int oplock_fd, 
+                           char *buffer, int buffer_len, 
+                           int timeout, BOOL *got_smb)
+{
+  fd_set fds;
+  int selrtn;
+  struct timeval to;
+
+  *got_smb = False;
+
+  /*
+   * Check to see if we already have a message on the udp queue.
+   * If so - copy and return it.
+   */
+
+  if(udp_msg_head)
+  {
+    udp_message_list *msg = udp_msg_head;
+    memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len));
+    udp_msg_head = msg->msg_next;
+
+    /* Free the message we just copied. */
+    free((char *)msg->msg_buf);
+    free((char *)msg);
+    return True;
+  }
+
+  FD_ZERO(&fds);
+  FD_SET(smbfd,&fds);
+  FD_SET(oplock_fd,&fds);
+
+  to.tv_sec = timeout / 1000;
+  to.tv_usec = (timeout % 1000) * 1000;
+
+  selrtn = sys_select(&fds,timeout>0?&to:NULL);
+
+  /* Check if error */
+  if(selrtn == -1) {
+    /* something is wrong. Maybe the socket is dead? */
+    smb_read_error = READ_ERROR;
+    return False;
+  } 
+    
+  /* Did we timeout ? */
+  if (selrtn == 0) {
+    smb_read_error = READ_TIMEOUT;
+    return False;
+  }
+
+  if (FD_ISSET(smbfd,&fds))
+  {
+    *got_smb = True;
+    return receive_smb(smbfd, buffer, 0);
+  }
+  else
+  {
+    return receive_local_message(oplock_fd, buffer, buffer_len, 0);
+  }
+}
 
 /****************************************************************************
   send an smb to a fd 
@@ -2408,8 +2605,8 @@ BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type)
   ret = (sendto(out_fd,buf,len,0,(struct sockaddr *)&sock_out,sizeof(sock_out)) >= 0);
 
   if (!ret)
-    DEBUG(0,("Packet send to %s(%d) failed ERRNO=%d\n",
-            inet_ntoa(ip),port,errno));
+    DEBUG(0,("Packet send to %s(%d) failed ERRNO=%s\n",
+            inet_ntoa(ip),port,strerror(errno)));
 
   close(out_fd);
   return(ret);
@@ -2487,7 +2684,12 @@ BOOL string_init(char **dest,char *src)
     }
   else
     {
-      *dest = (char *)malloc(l+1);
+      (*dest) = (char *)malloc(l+1);
+      if ((*dest) == NULL) {
+             DEBUG(0,("Out of memory in string_init\n"));
+             return False;
+      }
+
       strcpy(*dest,src);
     }
   return(True);
@@ -2656,35 +2858,35 @@ BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
 
   if (strequal(p1,"*")) return(True);
 
-  DEBUG(5,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
+  DEBUG(8,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
 
   if (trans2) {
-    strcpy(ebase,p1);
-    strcpy(sbase,p2);
+    fstrcpy(ebase,p1);
+    fstrcpy(sbase,p2);
   } else {
     if ((p=strrchr(p1,'.'))) {
       *p = 0;
-      strcpy(ebase,p1);
-      strcpy(eext,p+1);
+      fstrcpy(ebase,p1);
+      fstrcpy(eext,p+1);
     } else {
-      strcpy(ebase,p1);
+      fstrcpy(ebase,p1);
       eext[0] = 0;
     }
 
   if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) {
     *p = 0;
-    strcpy(sbase,p2);
-    strcpy(sext,p+1);
+    fstrcpy(sbase,p2);
+    fstrcpy(sext,p+1);
   } else {
-    strcpy(sbase,p2);
-    strcpy(sext,"");
+    fstrcpy(sbase,p2);
+    fstrcpy(sext,"");
   }
   }
 
   matched = do_match(sbase,ebase,case_sig) && 
     (trans2 || do_match(sext,eext,case_sig));
 
-  DEBUG(5,("mask_match returning %d\n", matched));
+  DEBUG(8,("mask_match returning %d\n", matched));
 
   return matched;
 }
@@ -2993,7 +3195,7 @@ BOOL get_myname(char *my_name,struct in_addr *ip)
       char *p = strchr(hostname,'.');
       if (p) *p = 0;
 
-      strcpy(my_name,hostname);
+      fstrcpy(my_name,hostname);
     }
 
   if (ip)
@@ -3211,6 +3413,10 @@ uint32 interpret_addr(char *str)
       DEBUG(3,("Get_Hostbyname: Unknown host. %s\n",str));
       return 0;
     }
+    if(hp->h_addr == NULL) {
+      DEBUG(3,("Get_Hostbyname: host address is invalid for host %s.\n",str));
+      return 0;
+    }
     putip((char *)&res,(char *)hp->h_addr);
   }
 
@@ -3361,7 +3567,7 @@ char *client_addr(void)
     return addr_buf;
   }
 
-  strcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
+  fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
 
   global_client_addr_done = True;
   return addr_buf;
@@ -3618,7 +3824,7 @@ char *readdirname(void *p)
 
   {
     static pstring buf;
-    strcpy(buf, dname);
+    pstrcpy(buf, dname);
     unix_to_dos(buf, True);
     dname = buf;
   }
@@ -3626,24 +3832,24 @@ char *readdirname(void *p)
   return(dname);
 }
 
-/*
Utility function used to decide if the last component 
of a path matches a (possibly wildcarded) entry in a namelist.
- */
+/*******************************************************************
+ Utility function used to decide if the last component 
+ of a path matches a (possibly wildcarded) entry in a namelist.
+********************************************************************/
 
 BOOL is_in_path(char *name, name_compare_entry *namelist)
 {
   pstring last_component;
   char *p;
 
-  DEBUG(5, ("is_in_path: %s\n", name));
+  DEBUG(8, ("is_in_path: %s\n", name));
 
   /* if we have no list it's obviously not in the path */
   if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL))) 
-        {
-    DEBUG(5,("is_in_path: no name list.\n"));
+  {
+    DEBUG(8,("is_in_path: no name list.\n"));
     return False;
-}
+  }
 
   /* Get the last component of the unix name. */
   p = strrchr(name, '/');
@@ -3657,7 +3863,7 @@ BOOL is_in_path(char *name, name_compare_entry *namelist)
       /* look for a wildcard match. */
       if (mask_match(last_component, namelist->name, case_sensitive, False))
       {
-         DEBUG(5,("is_in_path: mask match succeeded\n"));
+         DEBUG(8,("is_in_path: mask match succeeded\n"));
          return True;
       }
     }
@@ -3666,29 +3872,29 @@ BOOL is_in_path(char *name, name_compare_entry *namelist)
       if((case_sensitive && (strcmp(last_component, namelist->name) == 0))||
        (!case_sensitive && (StrCaseCmp(last_component, namelist->name) == 0)))
         {
-         DEBUG(5,("is_in_path: match succeeded\n"));
+         DEBUG(8,("is_in_path: match succeeded\n"));
          return True;
         }
     }
   }
-  DEBUG(5,("is_in_path: match not found\n"));
+  DEBUG(8,("is_in_path: match not found\n"));
  
   return False;
 }
 
-/*
Strip a '/' separated list into an array of 
name_compare_enties structures suitable for 
passing to is_in_path(). We do this for
speed so we can pre-parse all the names in the list 
and don't do it for each call to is_in_path().
namelist is modified here and is assumed to be 
a copy owned by the caller.
We also check if the entry contains a wildcard to
remove a potentially expensive call to mask_match
if possible.
-   */
-
+/*******************************************************************
+ Strip a '/' separated list into an array of 
+ name_compare_enties structures suitable for 
+ passing to is_in_path(). We do this for
+ speed so we can pre-parse all the names in the list 
+ and don't do it for each call to is_in_path().
+ namelist is modified here and is assumed to be 
+ a copy owned by the caller.
+ We also check if the entry contains a wildcard to
+ remove a potentially expensive call to mask_match
+ if possible.
+********************************************************************/
 void set_namearray(name_compare_entry **ppname_array, char *namelist)
 {
   char *name_end;
@@ -3829,7 +4035,7 @@ BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type)
 #endif
 
 
-  DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type));
+  DEBUG(8,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type));
 
   lock.l_type = type;
   lock.l_whence = SEEK_SET;
@@ -3877,7 +4083,7 @@ BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type)
     }
 
   /* everything went OK */
-  DEBUG(5,("Lock call successful\n"));
+  DEBUG(8,("Lock call successful\n"));
 
   return(True);
 #else
@@ -3923,7 +4129,7 @@ void file_unlock(int fd)
 is the name specified one of my netbios names
 returns true is it is equal, false otherwise
 ********************************************************************/
-BOOL is_myname(const char *s)
+BOOL is_myname(char *s)
 {
   int n;
   BOOL ret = False;
@@ -3973,3 +4179,166 @@ enum remote_arch_types get_remote_arch()
 {
   return ra_type;
 }
+
+
+/*******************************************************************
+skip past some unicode strings in a buffer
+********************************************************************/
+char *skip_unicode_string(char *buf,int n)
+{
+  while (n--)
+  {
+    while (*buf)
+      buf += 2;
+    buf += 2;
+  }
+  return(buf);
+}
+
+/*******************************************************************
+Return a ascii version of a unicode string
+Hack alert: uses fixed buffer and only handles ascii strings
+********************************************************************/
+#define MAXUNI 1024
+char *unistr(char *buf)
+{
+       static char lbufs[8][MAXUNI];
+       static int nexti;
+       char *lbuf = lbufs[nexti];
+       char *p;
+       nexti = (nexti+1)%8;
+       for (p = lbuf; *buf && p -lbuf < MAXUNI-2; p++, buf += 2)
+               *p = *buf;
+       *p = 0;
+       return lbuf;
+}
+
+/*******************************************************************
+strncpy for unicode strings
+********************************************************************/
+int unistrncpy(char *dst, char *src, int len)
+{
+       int num_wchars = 0;
+
+       while (*src && len > 0)
+       {
+               *dst++ = *src++;
+               *dst++ = *src++;
+               len--;
+               num_wchars++;
+       }
+       *dst++ = 0;
+       *dst++ = 0;
+
+       return num_wchars;
+}
+
+
+/*******************************************************************
+strcpy for unicode strings.  returns length (in num of wide chars)
+********************************************************************/
+int unistrcpy(char *dst, char *src)
+{
+       int num_wchars = 0;
+
+       while (*src)
+       {
+               *dst++ = *src++;
+               *dst++ = *src++;
+               num_wchars++;
+       }
+       *dst++ = 0;
+       *dst++ = 0;
+
+       return num_wchars;
+}
+
+
+/*******************************************************************
+safe string copy into a fstring
+********************************************************************/
+void fstrcpy(char *dest, char *src)
+{
+    int maxlength = sizeof(fstring) - 1;
+    if (!dest) {
+        DEBUG(0,("ERROR: NULL dest in fstrcpy\n"));
+        return;
+    }
+
+    if (!src) {
+        *dest = 0;
+        return;
+    }  
+      
+    while (maxlength-- && *src)
+        *dest++ = *src++;
+    *dest = 0;
+    if (*src) {
+        DEBUG(0,("ERROR: string overflow by %d in fstrcpy\n",
+             strlen(src)));
+    }    
+}   
+
+/*******************************************************************
+safe string copy into a pstring
+********************************************************************/
+void pstrcpy(char *dest, char *src)
+{
+    int maxlength = sizeof(pstring) - 1;
+    if (!dest) {
+        DEBUG(0,("ERROR: NULL dest in pstrcpy\n"));
+        return;
+    }
+   
+    if (!src) {
+        *dest = 0;
+        return;
+    }
+   
+    while (maxlength-- && *src)
+        *dest++ = *src++;
+    *dest = 0;
+    if (*src) {
+        DEBUG(0,("ERROR: string overflow by %d in pstrcpy\n",
+             strlen(src)));
+    }
+}  
+
+
+/*******************************************************************
+align a pointer to a multiple of 4 bytes
+********************************************************************/
+char *align4(char *q, char *base)
+{
+       if ((q - base) & 3)
+       {
+               q += 4 - ((q - base) & 3);
+       }
+       return q;
+}
+
+/*******************************************************************
+align a pointer to a multiple of 2 bytes
+********************************************************************/
+char *align2(char *q, char *base)
+{
+       if ((q - base) & 1)
+       {
+               q++;
+       }
+       return q;
+}
+
+/*******************************************************************
+align a pointer to a multiple of align_offset bytes.  looks like it
+will work for offsets of 0, 2 and 4...
+********************************************************************/
+char *align_offset(char *q, char *base, int align_offset_len)
+{
+       if (align_offset_len != 0 && ((q - base) & (align_offset_len-1)))
+       {
+               q += align_offset_len - ((q - base) & (align_offset_len));
+       }
+       return q;
+}
+