merge from the autoconf2 branch to the main branch
[samba.git] / source / lib / util.c
index 812e59769e5161c02ed85a80569f1843b5b86bb6..8d1f61931890fc54965d7ffdd7704ae8cc16dab7 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    Samba utility functions
-   Copyright (C) Andrew Tridgell 1992-1997
+   Copyright (C) Andrew Tridgell 1992-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
 
 #include "includes.h"
 
+#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
+#ifdef NISPLUS_HOME
+#include <rpcsvc/nis.h>
+#else
+#include "rpcsvc/ypclnt.h"
+#endif
+#endif
+
+#ifdef WITH_SSL
+#include <ssl.h>
+#undef Realloc  /* SSLeay defines this and samba has a function of this name */
+extern SSL  *ssl;
+extern int  sslFd;
+#endif  /* WITH_SSL */
+
 pstring scope = "";
 
 int DEBUGLEVEL = 1;
@@ -55,7 +70,7 @@ int trans_num = 0;
 int case_default = CASE_LOWER;
 
 pstring debugf = "";
-int syslog_level;
+int syslog_level = 0;
 
 /* the following control case operations - they are put here so the
    client can link easily */
@@ -72,9 +87,14 @@ static enum remote_arch_types ra_type = RA_UNKNOWN;
 fstring remote_proto="UNKNOWN";
 pstring myhostname="";
 pstring user_socket_options="";   
+
 pstring sesssetup_user="";
-pstring myname = "";
-fstring myworkgroup = "";
+pstring samlogon_user="";
+
+BOOL sam_logon_in_ssb = False;
+
+pstring global_myname = "";
+fstring global_myworkgroup = "";
 char **my_netbios_names;
 
 int smb_read_error = 0;
@@ -83,20 +103,64 @@ static BOOL stdout_logging = False;
 
 static char *filename_dos(char *path,char *buf);
 
+#if defined(SIGUSR2)
+/******************************************************************************
+ catch a sigusr2 - decrease the debug log level.
+ *****************************************************************************/
+int sig_usr2(void)
+{  
+  BlockSignals( True, SIGUSR2);
+  DEBUGLEVEL--; 
+   
+  if(DEBUGLEVEL < 0) 
+    DEBUGLEVEL = 0; 
+
+  DEBUG( 0, ( "Got SIGUSR2 set debug level to %d.\n", DEBUGLEVEL ) );
+   
+  BlockSignals( False, SIGUSR2);
+  CatchSignal(SIGUSR2, SIGNAL_CAST sig_usr2);
+
+  return(0);
+}  
+#endif /* SIGUSR1 */
+   
+#if defined(SIGUSR1)
+/******************************************************************************
+ catch a sigusr1 - increase the debug log level. 
+ *****************************************************************************/
+int sig_usr1(void)
+{
+  BlockSignals( True, SIGUSR1);
+  DEBUGLEVEL++;
+
+  if(DEBUGLEVEL > 10)
+    DEBUGLEVEL = 10;
+
+  DEBUG( 0, ( "Got SIGUSR1 set debug level to %d.\n", DEBUGLEVEL ) );
+
+  BlockSignals( False, SIGUSR1);
+  CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1);
+  return(0);
+}
+#endif /* SIGUSR1 */
+
+
 /*******************************************************************
   get ready for syslog stuff
   ******************************************************************/
 void setup_logging(char *pname,BOOL interactive)
 {
-#ifdef SYSLOG
+#ifdef WITH_SYSLOG
   if (!interactive) {
     char *p = strrchr(pname,'/');
     if (p) pname = p+1;
 #ifdef LOG_DAEMON
-    openlog(pname, LOG_PID, LOG_DAEMON);
-#else /* LOG_DAEMON - for old systems that have no facility codes. */
+    openlog(pname, LOG_PID, SYSLOG_FACILITY);
+#else /* for old systems that have no facility codes. */
     openlog(pname, LOG_PID);
-#endif /* LOG_DAEMON */
+#endif
   }
 #endif
   if (interactive) {
@@ -114,61 +178,87 @@ reopen the log files
 ****************************************************************************/
 void reopen_logs(void)
 {
-  extern FILE *dbf;
   pstring fname;
   
   if (DEBUGLEVEL > 0)
-    {
-      strcpy(fname,debugf);
-      if (lp_loaded() && (*lp_logfile()))
-       strcpy(fname,lp_logfile());
+  {
+    pstrcpy(fname,debugf);
+    if (lp_loaded() && (*lp_logfile()))
+      pstrcpy(fname,lp_logfile());
 
-      if (!strcsequal(fname,debugf) || !dbf || !file_exist(debugf,NULL))
-       {
-         int oldumask = umask(022);
-         strcpy(debugf,fname);
-         if (dbf) fclose(dbf);
-         if (append_log)
-           dbf = fopen(debugf,"a");
-         else
-           dbf = fopen(debugf,"w");
-         if (dbf) setbuf(dbf,NULL);
-         umask(oldumask);
-       }
+    if (!strcsequal(fname,debugf) || !dbf || !file_exist(debugf,NULL))
+    {
+      int oldumask = umask(022);
+      pstrcpy(debugf,fname);
+      if (dbf)
+        fclose(dbf);
+      if (append_log)
+        dbf = fopen(debugf,"a");
+      else
+        dbf = fopen(debugf,"w");
+      /*
+       * Fix from klausr@ITAP.Physik.Uni-Stuttgart.De
+       * to fix problem where smbd's that generate less
+       * than 100 messages keep growing the log.
+       */
+      force_check_log_size();
+      if (dbf)
+        setbuf(dbf,NULL);
+      umask(oldumask);
     }
+  }
   else
+  {
+    if (dbf)
     {
-      if (dbf)
-       {
-         fclose(dbf);
-         dbf = NULL;
-       }
+      fclose(dbf);
+      dbf = NULL;
     }
+  }
 }
 
+/*******************************************************************
+ Number of debug messages that have been output. 
+ Used to check log size.
+********************************************************************/
+
+static int debug_count=0;
+
+/*******************************************************************
+ Force a check of the log size.
+********************************************************************/
+
+void force_check_log_size(void)
+{
+  debug_count = 100;
+}
 
 /*******************************************************************
-check if the log has grown too big
+ Check if the log has grown too big
 ********************************************************************/
+
 static void check_log_size(void)
 {
-  static int debug_count=0;
   int maxlog;
   struct stat st;
 
-  if (debug_count++ < 100) return;
+  if (debug_count++ < 100 || getuid() != 0)
+    return;
 
   maxlog = lp_max_log_size() * 1024;
-  if (!dbf || maxlog <= 0) return;
+  if (!dbf || maxlog <= 0)
+    return;
 
   if (fstat(fileno(dbf),&st) == 0 && st.st_size > maxlog) {
-    fclose(dbf); dbf = NULL;
+    fclose(dbf);
+    dbf = NULL;
     reopen_logs();
     if (dbf && file_size(debugf) > maxlog) {
       pstring name;
-      fclose(dbf); dbf = NULL;
-      sprintf(name,"%s.old",debugf);
-      sys_rename(debugf,name);
+      fclose(dbf);
+      dbf = NULL;
+      slprintf(name,sizeof(name)-1,"%s.old",debugf);
+      rename(debugf,name);
       reopen_logs();
     }
   }
@@ -180,7 +270,7 @@ static void check_log_size(void)
 write an debug message on the debugfile. This is called by the DEBUG
 macro
 ********************************************************************/
-#ifdef __STDC__
+#ifdef HAVE_STDARG_H
  int Debug1(char *format_str, ...)
 {
 #else
@@ -190,9 +280,10 @@ va_dcl
   char *format_str;
 #endif
   va_list ap;  
-  
+  int old_errno = errno;
+
   if (stdout_logging) {
-#ifdef __STDC__
+#ifdef HAVE_STDARG_H
     va_start(ap, format_str);
 #else
     va_start(ap);
@@ -200,26 +291,31 @@ va_dcl
 #endif
     vfprintf(dbf,format_str,ap);
     va_end(ap);
+    errno = old_errno;
     return(0);
   }
   
-#ifdef SYSLOG
+#ifdef WITH_SYSLOG
   if (!lp_syslog_only())
 #endif  
     {
-      if (!dbf) 
-       {
-         int oldumask = umask(022);
-         dbf = fopen(debugf,"w");
-         umask(oldumask);
-         if (dbf)
-           setbuf(dbf,NULL);
-         else
-           return(0);
-       }
+      if (!dbf) {
+             int oldumask = umask(022);
+              if(append_log)
+                dbf = fopen(debugf,"a");
+              else
+                dbf = fopen(debugf,"w");
+             umask(oldumask);
+             if (dbf) {
+                     setbuf(dbf,NULL);
+             } else {
+                     errno = old_errno;
+                     return(0);
+             }
+      }
     }
 
-#ifdef SYSLOG
+#ifdef WITH_SYSLOG
   if (syslog_level < lp_syslog())
     {
       /* 
@@ -242,13 +338,13 @@ va_dcl
       else
        priority = priority_map[syslog_level];
       
-#ifdef __STDC__
+#ifdef HAVE_STDARG_H
       va_start(ap, format_str);
 #else
       va_start(ap);
       format_str = va_arg(ap,char *);
 #endif
-      vsprintf(msgbuf, format_str, ap);
+      vslprintf(msgbuf, sizeof(msgbuf)-1,format_str, ap);
       va_end(ap);
       
       msgbuf[255] = '\0';
@@ -256,11 +352,11 @@ va_dcl
     }
 #endif
   
-#ifdef SYSLOG
+#ifdef WITH_SYSLOG
   if (!lp_syslog_only())
 #endif
     {
-#ifdef __STDC__
+#ifdef HAVE_STDARG_H
       va_start(ap, format_str);
 #else
       va_start(ap);
@@ -273,6 +369,8 @@ va_dcl
 
   check_log_size();
 
+  errno = old_errno;
+
   return(0);
 }
 
@@ -382,66 +480,20 @@ char **toktocliplist(int *ctok, char *sep)
   return ret;
 }
 
-#ifndef HAVE_MEMMOVE
-/*******************************************************************
-safely copies memory, ensuring no overlap problems.
-this is only used if the machine does not have it's own memmove().
-this is not the fastest algorithm in town, but it will do for our
-needs.
-********************************************************************/
-void *MemMove(void *dest,void *src,int size)
-{
-  unsigned long d,s;
-  int i;
-  if (dest==src || !size) return(dest);
-
-  d = (unsigned long)dest;
-  s = (unsigned long)src;
-
-  if ((d >= (s+size)) || (s >= (d+size))) {
-    /* no overlap */
-    memcpy(dest,src,size);
-    return(dest);
-  }
 
-  if (d < s)
-    {
-      /* we can forward copy */
-      if (s-d >= sizeof(int) && 
-         !(s%sizeof(int)) && !(d%sizeof(int)) && !(size%sizeof(int))) {
-       /* do it all as words */
-       int *idest = (int *)dest;
-       int *isrc = (int *)src;
-       size /= sizeof(int);
-       for (i=0;i<size;i++) idest[i] = isrc[i];
-      } else {
-       /* simplest */
-       char *cdest = (char *)dest;
-       char *csrc = (char *)src;
-       for (i=0;i<size;i++) cdest[i] = csrc[i];
-      }
-    }
-  else
-    {
-      /* must backward copy */
-      if (d-s >= sizeof(int) && 
-         !(s%sizeof(int)) && !(d%sizeof(int)) && !(size%sizeof(int))) {
-       /* do it all as words */
-       int *idest = (int *)dest;
-       int *isrc = (int *)src;
-       size /= sizeof(int);
-       for (i=size-1;i>=0;i--) idest[i] = isrc[i];
-      } else {
-       /* simplest */
-       char *cdest = (char *)dest;
-       char *csrc = (char *)src;
-       for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
-      }      
-    }
-  return(dest);
-}
-#endif
+/* ************************************************************************* **
+ * Duplicate a block of memory.
+ * ************************************************************************* **
+ */
+void *mem_dup( void *from, int size )
+  {
+  void *tmp;
 
+  tmp = malloc( size );
+  if( NULL != tmp )
+    (void)memcpy( tmp, from, size );
+  return( tmp );
+  } /* mem_dup */
 
 /****************************************************************************
 prompte a dptr (to make it recently used)
@@ -514,7 +566,7 @@ set user socket options
 ****************************************************************************/
 void set_socket_options(int fd, char *options)
 {
-  string tok;
+  fstring tok;
 
   while (next_token(&options,tok," \t,"))
     {
@@ -572,6 +624,10 @@ void set_socket_options(int fd, char *options)
 ****************************************************************************/
 void close_sockets(void )
 {
+#ifdef WITH_SSL
+  sslutil_disconnect(Client);
+#endif /* WITH_SSL */
+
   close(Client);
   Client = 0;
 }
@@ -684,48 +740,61 @@ static int name_interpret(char *in,char *out)
 
 /****************************************************************************
 mangle a name into netbios format
+
+  Note:  <Out> must be (33 + strlen(scope) + 2) bytes long, at minimum.
 ****************************************************************************/
-int name_mangle(char *In,char *Out,char name_type)
-{
-  fstring name;
-  char buf[20];
-  char *in = (char *)&buf[0];
-  char *out = (char *)Out;
-  char *p, *label;
-  int i;
+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( '*' == In[0] )
+    buf[0] = '*';
+  else
+    (void)slprintf( buf, sizeof(buf) - 1, "%-15.15s%c", In, name_type );
 
-  if (In[0] != '*') {
-    StrnCpy(name,In,sizeof(name)-1);
-    sprintf(buf,"%-15.15s%c",name,name_type);
-  } else {
-    buf[0]='*';
-    memset(&buf[1],0,16);
-  }
+  /* Place the length of the first field into the output buffer. */
+  p[0] = 32;
+  p++;
 
-  *out++ = 32;
-  for (i=0;i<16;i++) {
-    char c = toupper(in[i]);
-    out[i*2] = (c>>4) + 'A';
-    out[i*2+1] = (c & 0xF) + 'A';
-  }
-  out[32]=0;
-  out += 32;
-  
-  label = scope;
-  while (*label)
+  /* Now convert the name to the rfc1001/1002 format. */
+  for( i = 0; i < 16; i++ )
     {
-      p = strchr(label, '.');
-      if (p == 0)
-       p = label + strlen(label);
-      *out++ = p - label;
-      memcpy(out, label, p - label);
-      out += p - label;
-      label += p - label + (*p == '.');
+    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 != scope; i++, len++ )
+    {
+    switch( 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  = 0;
+        break;
+      default:
+        p[len+1] = scope[i];
+        break;
+      }
     }
-  *out = 0;
-  return(name_len(Out));
-}
 
+  return( name_len(Out) );
+  } /* name_mangle */
 
 /*******************************************************************
   check if a file exists
@@ -789,16 +858,16 @@ return a string representing an attribute for a file
 ********************************************************************/
 char *attrib_string(int mode)
 {
-  static char attrstr[10];
+  static fstring attrstr;
 
   attrstr[0] = 0;
 
-  if (mode & aVOLID) strcat(attrstr,"V");
-  if (mode & aDIR) strcat(attrstr,"D");
-  if (mode & aARCH) strcat(attrstr,"A");
-  if (mode & aHIDDEN) strcat(attrstr,"H");
-  if (mode & aSYSTEM) strcat(attrstr,"S");
-  if (mode & aRONLY) strcat(attrstr,"R");        
+  if (mode & aVOLID) fstrcat(attrstr,"V");
+  if (mode & aDIR) fstrcat(attrstr,"D");
+  if (mode & aARCH) fstrcat(attrstr,"A");
+  if (mode & aHIDDEN) fstrcat(attrstr,"H");
+  if (mode & aSYSTEM) fstrcat(attrstr,"S");
+  if (mode & aRONLY) fstrcat(attrstr,"R");       
 
   return(attrstr);
 }
@@ -814,6 +883,15 @@ int StrCaseCmp(char *s, char *t)
      asynchronous upper to lower mapping.
    */
 #if !defined(KANJI_WIN95_COMPATIBILITY)
+  /*
+   * For completeness we should put in equivalent code for code pages
+   * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but
+   * doubt anyone wants Samba to behave differently from Win95 and WinNT
+   * here. They both treat full width ascii characters as case senstive
+   * filenames (ie. they don't do the work we do here).
+   * JRA.
+   */
+
   if(lp_client_code_page() == KANJI_CODEPAGE)
   {
     /* Win95 treats full width ascii characters as case sensitive. */
@@ -878,6 +956,15 @@ int StrnCaseCmp(char *s, char *t, int n)
      asynchronous upper to lower mapping.
    */
 #if !defined(KANJI_WIN95_COMPATIBILITY)
+  /*
+   * For completeness we should put in equivalent code for code pages
+   * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but
+   * doubt anyone wants Samba to behave differently from Win95 and WinNT
+   * here. They both treat full width ascii characters as case senstive
+   * filenames (ie. they don't do the work we do here).
+   * JRA. 
+   */
+
   if(lp_client_code_page() == KANJI_CODEPAGE)
   {
     /* Win95 treats full width ascii characters as case sensitive. */
@@ -926,10 +1013,11 @@ int StrnCaseCmp(char *s, char *t, int n)
   else
 #endif /* KANJI_WIN95_COMPATIBILITY */
   {
-    while (n-- && *s && *t && toupper(*s) == toupper(*t))
+    while (n && *s && *t && toupper(*s) == toupper(*t))
     {
       s++;
       t++;
+      n--;
     }
 
     /* not run out of chars - strings are different lengths */
@@ -984,6 +1072,15 @@ void strlower(char *s)
   while (*s)
   {
 #if !defined(KANJI_WIN95_COMPATIBILITY)
+  /*
+   * For completeness we should put in equivalent code for code pages
+   * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but
+   * doubt anyone wants Samba to behave differently from Win95 and WinNT
+   * here. They both treat full width ascii characters as case senstive
+   * filenames (ie. they don't do the work we do here).
+   * JRA. 
+   */
+
     if(lp_client_code_page() == KANJI_CODEPAGE)
     {
       /* Win95 treats full width ascii characters as case sensitive. */
@@ -1007,9 +1104,15 @@ void strlower(char *s)
     else
 #endif /* KANJI_WIN95_COMPATIBILITY */
     {
-      if (isupper(*s))
-        *s = tolower(*s);
-      s++;
+      int skip = skip_multibyte_char( *s );
+      if( skip != 0 )
+        s += skip;
+      else
+      {
+        if (isupper(*s))
+          *s = tolower(*s);
+        s++;
+      }
     }
   }
 }
@@ -1022,6 +1125,15 @@ void strupper(char *s)
   while (*s)
   {
 #if !defined(KANJI_WIN95_COMPATIBILITY)
+  /*
+   * For completeness we should put in equivalent code for code pages
+   * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but
+   * doubt anyone wants Samba to behave differently from Win95 and WinNT
+   * here. They both treat full width ascii characters as case senstive
+   * filenames (ie. they don't do the work we do here).
+   * JRA. 
+   */
+
     if(lp_client_code_page() == KANJI_CODEPAGE)
     {
       /* Win95 treats full width ascii characters as case sensitive. */
@@ -1045,9 +1157,15 @@ void strupper(char *s)
     else
 #endif /* KANJI_WIN95_COMPATIBILITY */
     {
-      if (islower(*s))
-        *s = toupper(*s);
-      s++;
+      int skip = skip_multibyte_char( *s );
+      if( skip != 0 )
+        s += skip;
+      else
+      {
+        if (islower(*s))
+          *s = toupper(*s);
+        s++;
+      }
     }
   }
 }
@@ -1080,25 +1198,13 @@ BOOL strisnormal(char *s)
 ****************************************************************************/
 void string_replace(char *s,char oldc,char newc)
 {
+  int skip;
   while (*s)
   {
-#if !defined(KANJI_WIN95_COMPATIBILITY)
-    if(lp_client_code_page() == KANJI_CODEPAGE)
-    {
-      /* Win95 treats full width ascii characters as case sensitive. */
-      if (is_shift_jis (*s))
-        s += 2;
-      else if (is_kana (*s))
-        s++;
-      else
-      {
-        if (oldc == *s)
-          *s = newc;
-        s++;
-      }
-    }
+    skip = skip_multibyte_char( *s );
+    if( skip != 0 )
+      s += skip;
     else
-#endif /* KANJI_WIN95_COMPATIBILITY */
     {
       if (oldc == *s)
         *s = newc;
@@ -1117,9 +1223,9 @@ void unix_format(char *fname)
 
   if (*fname == '/')
     {
-      strcpy(namecopy,fname);
-      strcpy(fname,".");
-      strcat(fname,namecopy);
+      pstrcpy(namecopy,fname);
+      pstrcpy(fname,".");
+      pstrcat(fname,namecopy);
     }  
 }
 
@@ -1131,63 +1237,50 @@ void dos_format(char *fname)
   string_replace(fname,'/','\\');
 }
 
-
 /*******************************************************************
   show a smb message structure
 ********************************************************************/
 void show_msg(char *buf)
 {
-  int i;
-  int j;
-  int bcc=0;
-  if (DEBUGLEVEL < 5)
-    return;
-
-  DEBUG(5,("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\nsmb_flg=%d\nsmb_flg2=%d\n",
-         smb_len(buf),
-         (int)CVAL(buf,smb_com),
-         (int)CVAL(buf,smb_rcls),
-         (int)CVAL(buf,smb_reh),
-         (int)SVAL(buf,smb_err),
-         (int)CVAL(buf,smb_flg),
-         (int)SVAL(buf,smb_flg2)));
-  DEBUG(5,("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\nsmt_wct=%d\n",
-         (int)SVAL(buf,smb_tid),
-         (int)SVAL(buf,smb_pid),
-         (int)SVAL(buf,smb_uid),
-         (int)SVAL(buf,smb_mid),
-         (int)CVAL(buf,smb_wct)));
-  for (i=0;i<(int)CVAL(buf,smb_wct);i++)
-    DEBUG(5,("smb_vwv[%d]=%d (0x%X)\n",i,
-         SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i)));
-  bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct)));
-  DEBUG(5,("smb_bcc=%d\n",bcc));
-  if (DEBUGLEVEL < 10)
-    return;
-  for (i = 0; i < MIN(bcc, 256); i += 16)
-  {
-    for (j = 0; j < 16 && i+j < MIN(bcc,256); j++)
-    {
+       int i;
+       int bcc=0;
+
+       if (DEBUGLEVEL < 5) return;
+
+       DEBUG(5,("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\nsmb_flg=%d\nsmb_flg2=%d\n",
+                       smb_len(buf),
+                       (int)CVAL(buf,smb_com),
+                       (int)CVAL(buf,smb_rcls),
+                       (int)CVAL(buf,smb_reh),
+                       (int)SVAL(buf,smb_err),
+                       (int)CVAL(buf,smb_flg),
+                       (int)SVAL(buf,smb_flg2)));
+       DEBUG(5,("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\nsmt_wct=%d\n",
+                       (int)SVAL(buf,smb_tid),
+                       (int)SVAL(buf,smb_pid),
+                       (int)SVAL(buf,smb_uid),
+                       (int)SVAL(buf,smb_mid),
+                       (int)CVAL(buf,smb_wct)));
+
+       for (i=0;i<(int)CVAL(buf,smb_wct);i++)
+       {
+               DEBUG(5,("smb_vwv[%d]=%d (0x%X)\n",i,
+                       SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i)));
+       }
 
-      DEBUG(10,("%2X ",CVAL(smb_buf(buf),i+j)));
-      if (j == 7) DEBUG(10, ("  "));
+       bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct)));
 
-    }
-    DEBUG(10,("  "));  
+       DEBUG(5,("smb_bcc=%d\n",bcc));
 
-    for (j = 0; j < 16 && i+j < MIN(bcc,256); j++)
-    {
-      unsigned char c = CVAL(smb_buf(buf),i+j);
-      if (c < 32 || c > 128) c = '.';
-      DEBUG(10,("%c",c));
+       if (DEBUGLEVEL < 10) return;
 
-      if (j == 7) DEBUG(10, ("  "));
-    }
+       if (DEBUGLEVEL < 50)
+       {
+               bcc = MIN(bcc, 512);
+       }
 
-  DEBUG(10,("\n"));  
-}
+       dump_data(10, smb_buf(buf), bcc);
 }
-
 /*******************************************************************
   return the length of an smb packet
 ********************************************************************/
@@ -1328,13 +1421,13 @@ 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;
       else
        *s = 0;
-      strcat(s,s1);
+      pstrcat(s,s1);
     }  
 
   trim_string(s,NULL,"\\..");
@@ -1358,7 +1451,7 @@ void unix_clean_name(char *s)
   if(strncmp(s, "./", 2) == 0) {
     trim_string(s, "./", NULL);
     if(*s == 0)
-      strcpy(s,"./");
+      pstrcpy(s,"./");
   }
 
   while ((p = strstr(s,"/../")) != NULL)
@@ -1366,13 +1459,13 @@ 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;
       else
        *s = 0;
-      strcat(s,s1);
+      pstrcat(s,s1);
     }  
 
   trim_string(s,NULL,"/..");
@@ -1393,7 +1486,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);
 }
 
@@ -1465,7 +1558,7 @@ char *GetWd(char *str)
                    st.st_dev == st2.st_dev &&
                    (st2.st_mode & S_IFMT) == S_IFDIR)
                  {
-                   strcpy (str, ino_list[i].text);
+                   pstrcpy (str, ino_list[i].text);
 
                    /* promote it for future use */
                    array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
@@ -1492,7 +1585,7 @@ char *GetWd(char *str)
       return (NULL);
     }
 
-  strcpy(str,s);
+  pstrcpy(str,s);
 
   DEBUG(5,("GetWd %s, inode %d, dev %x\n",s,(int)st.st_ino,(int)st.st_dev));
 
@@ -1525,12 +1618,12 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
 #else
   pstring dir2;
   pstring wd;
-  pstring basename;
+  pstring base_name;
   pstring newname;
   char *p=NULL;
   BOOL relative = (*s != '/');
 
-  *dir2 = *wd = *basename = *newname = 0;
+  *dir2 = *wd = *base_name = *newname = 0;
 
   if (widelinks)
     {
@@ -1543,7 +1636,7 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
        }
 
       if (strlen(s) == 0)
-        strcpy(s,"./");
+        pstrcpy(s,"./");
 
       return(True);
     }
@@ -1553,8 +1646,8 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
   /* remove any double slashes */
   string_sub(s,"//","/");
 
-  strcpy(basename,s);
-  p = strrchr(basename,'/');
+  pstrcpy(base_name,s);
+  p = strrchr(base_name,'/');
 
   if (!p)
     return(True);
@@ -1579,7 +1672,7 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
     }
 
 
-    if (p && (p != basename))
+    if (p && (p != base_name))
       {
        *p = 0;
        if (strcmp(p+1,".")==0)
@@ -1588,10 +1681,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
          *p = '/';
       }
 
-  if (ChDir(basename) != 0)
+  if (ChDir(base_name) != 0)
     {
       ChDir(wd);
-      DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,basename));
+      DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,base_name));
       return(False);
     }
 
@@ -1602,10 +1695,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
       return(False);
     }
 
-  if (p && (p != basename))
+  if (p && (p != base_name))
     {
-      strcat(newname,"/");
-      strcat(newname,p+1);
+      pstrcat(newname,"/");
+      pstrcat(newname,p+1);
     }
 
   {
@@ -1623,18 +1716,18 @@ 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);
 
   if (strlen(s) == 0)
-    strcpy(s,"./");
+    pstrcpy(s,"./");
 
   DEBUG(3,("reduced to %s\n",s));
   return(True);
@@ -1652,10 +1745,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,42 +1772,42 @@ 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,"");
+      pstrcpy(mext,"");
       if (strlen(mbeg) > 8)
        {
-         strcpy(mext,mbeg + 8);
+         pstrcpy(mext,mbeg + 8);
          mbeg[8] = 0;
        }
     }
 
   if (*mbeg == 0)
-    strcpy(mbeg,"????????");
+    pstrcpy(mbeg,"????????");
   if ((*mext == 0) && doext && !hasdot)
-    strcpy(mext,"???");
+    pstrcpy(mext,"???");
 
   if (strequal(mbeg,"*") && *mext==0) 
-    strcpy(mext,"*");
+    pstrcpy(mext,"*");
 
   /* expand *'s */
   expand_one(mbeg,8);
   if (*mext)
     expand_one(mext,3);
 
-  strcpy(Mask,dirpart);
-  if (*dirpart || absolute) strcat(Mask,"\\");
-  strcat(Mask,mbeg);
-  strcat(Mask,".");
-  strcat(Mask,mext);
+  pstrcpy(Mask,dirpart);
+  if (*dirpart || absolute) pstrcat(Mask,"\\");
+  pstrcat(Mask,mbeg);
+  pstrcat(Mask,".");
+  pstrcat(Mask,mext);
 
   DEBUG(6,("Mask expanded to [%s]\n",Mask));
 }  
@@ -1728,6 +1821,15 @@ BOOL strhasupper(char *s)
   while (*s) 
   {
 #if !defined(KANJI_WIN95_COMPATIBILITY)
+  /*
+   * For completeness we should put in equivalent code for code pages
+   * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but
+   * doubt anyone wants Samba to behave differently from Win95 and WinNT
+   * here. They both treat full width ascii characters as case senstive
+   * filenames (ie. they don't do the work we do here).
+   * JRA. 
+   */
+
     if(lp_client_code_page() == KANJI_CODEPAGE)
     {
       /* Win95 treats full width ascii characters as case sensitive. */
@@ -1745,9 +1847,14 @@ BOOL strhasupper(char *s)
     else
 #endif /* KANJI_WIN95_COMPATIBILITY */
     {
-      if (isupper(*s))
-        return(True);
-      s++;
+      int skip = skip_multibyte_char( *s );
+      if( skip != 0 )
+        s += skip;
+      else {
+        if (isupper(*s))
+          return(True);
+        s++;
+      }
     }
   }
   return(False);
@@ -1761,6 +1868,15 @@ BOOL strhaslower(char *s)
   while (*s) 
   {
 #if !defined(KANJI_WIN95_COMPATIBILITY)
+  /*
+   * For completeness we should put in equivalent code for code pages
+   * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but
+   * doubt anyone wants Samba to behave differently from Win95 and WinNT
+   * here. They both treat full width ascii characters as case senstive
+   * filenames (ie. they don't do the work we do here).
+   * JRA. 
+   */
+
     if(lp_client_code_page() == KANJI_CODEPAGE)
     {
       /* Win95 treats full width ascii characters as case sensitive. */
@@ -1786,9 +1902,14 @@ BOOL strhaslower(char *s)
     else
 #endif /* KANJI_WIN95_COMPATIBILITY */
     {
-      if (islower(*s))
-        return(True);
-      s++;
+      int skip = skip_multibyte_char( *s );
+      if( skip != 0 )
+        s += skip;
+      else {
+        if (islower(*s))
+          return(True);
+        s++;
+      }
     }
   }
   return(False);
@@ -1802,6 +1923,15 @@ int count_chars(char *s,char c)
   int count=0;
 
 #if !defined(KANJI_WIN95_COMPATIBILITY)
+  /*
+   * For completeness we should put in equivalent code for code pages
+   * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but
+   * doubt anyone wants Samba to behave differently from Win95 and WinNT
+   * here. They both treat full width ascii characters as case senstive
+   * filenames (ie. they don't do the work we do here).
+   * JRA. 
+   */
+
   if(lp_client_code_page() == KANJI_CODEPAGE)
   {
     /* Win95 treats full width ascii characters as case sensitive. */
@@ -1822,9 +1952,14 @@ int count_chars(char *s,char c)
   {
     while (*s) 
     {
-      if (*s == c)
-        count++;
-      s++;
+      int skip = skip_multibyte_char( *s );
+      if( skip != 0 )
+        s += skip;
+      else {
+        if (*s == c)
+          count++;
+        s++;
+      }
     }
   }
   return(count);
@@ -1839,7 +1974,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;
@@ -1934,6 +2069,10 @@ int write_socket(int fd,char *buf,int len)
   ret = write_data(fd,buf,len);
       
   DEBUG(6,("write_socket(%d,%d) wrote %d\n",fd,len,ret));
+  if(ret <= 0)
+    DEBUG(0,("write_socket: Error writing %d bytes to socket %d: ERRNO = %s\n", 
+       len, fd, strerror(errno) ));
+
   return(ret);
 }
 
@@ -1943,20 +2082,23 @@ read from a socket
 int read_udp_socket(int fd,char *buf,int len)
 {
   int ret;
-  struct sockaddr sock;
+  struct sockaddr_in sock;
   int socklen;
   
   socklen = sizeof(sock);
   bzero((char *)&sock,socklen);
   bzero((char *)&lastip,sizeof(lastip));
-  ret = recvfrom(fd,buf,len,0,&sock,&socklen);
+  ret = recvfrom(fd,buf,len,0,(struct sockaddr *)&sock,&socklen);
   if (ret <= 0) {
     DEBUG(2,("read socket failed. ERRNO=%s\n",strerror(errno)));
     return(0);
   }
 
-  lastip = *(struct in_addr *) &sock.sa_data[2];
-  lastport = ntohs(((struct sockaddr_in *)&sock)->sin_port);
+  lastip = sock.sin_addr;
+  lastport = ntohs(sock.sin_port);
+
+  DEBUG(10,("read_udp_socket: lastip %s lastport %d read: %d\n",
+             inet_ntoa(lastip), lastport, ret));
 
   return(ret);
 }
@@ -1984,7 +2126,16 @@ int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out)
     if (mincnt == 0) mincnt = maxcnt;
 
     while (nread < mincnt) {
+#ifdef WITH_SSL
+      if(fd == sslFd){
+        readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+      }else{
+        readret = read(fd, buf + nread, maxcnt - nread);
+      }
+#else /* WITH_SSL */
       readret = read(fd, buf + nread, maxcnt - nread);
+#endif /* WITH_SSL */
+
       if (readret == 0) {
        smb_read_error = READ_EOF;
        return -1;
@@ -2029,7 +2180,16 @@ int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out)
        return -1;
       }
       
-      readret = read(fd, buf+nread, maxcnt-nread);
+#ifdef WITH_SSL
+    if(fd == sslFd){
+      readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+    }else{
+      readret = read(fd, buf + nread, maxcnt - nread);
+    }
+#else /* WITH_SSL */
+    readret = read(fd, buf+nread, maxcnt-nread);
+#endif /* WITH_SSL */
+
       if (readret == 0) {
        /* we got EOF on the file descriptor */
        smb_read_error = READ_EOF;
@@ -2112,18 +2272,29 @@ int read_data(int fd,char *buffer,int N)
   smb_read_error = 0;
 
   while (total < N)
-    {
+  {
+#ifdef WITH_SSL
+    if(fd == sslFd){
+      ret = SSL_read(ssl, buffer + total, N - total);
+    }else{
       ret = read(fd,buffer + total,N - total);
-      if (ret == 0) {
-       smb_read_error = READ_EOF;
-       return 0;
-      }
-      if (ret == -1) {
-       smb_read_error = READ_ERROR;
-       return -1;
-      }
-      total += ret;
     }
+#else /* WITH_SSL */
+    ret = read(fd,buffer + total,N - total);
+#endif /* WITH_SSL */
+
+    if (ret == 0)
+    {
+      smb_read_error = READ_EOF;
+      return 0;
+    }
+    if (ret == -1)
+    {
+      smb_read_error = READ_ERROR;
+      return -1;
+    }
+    total += ret;
+  }
   return total;
 }
 
@@ -2137,14 +2308,22 @@ int write_data(int fd,char *buffer,int N)
   int ret;
 
   while (total < N)
-    {
+  {
+#ifdef WITH_SSL
+    if(fd == sslFd){
+      ret = SSL_write(ssl,buffer + total,N - total);
+    }else{
       ret = write(fd,buffer + total,N - total);
+    }
+#else /* WITH_SSL */
+    ret = write(fd,buffer + total,N - total);
+#endif /* WITH_SSL */
 
-      if (ret == -1) return -1;
-      if (ret == 0) return total;
+    if (ret == -1) return -1;
+    if (ret == 0) return total;
 
-      total += ret;
-    }
+    total += ret;
+  }
   return total;
 }
 
@@ -2228,38 +2407,30 @@ int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align)
 
 /****************************************************************************
 read 4 bytes of a smb packet and return the smb length of the packet
-possibly store the result in the buffer
+store the result in the buffer
+This version of the function will return a length of zero on receiving
+a keepalive packet.
 ****************************************************************************/
-int read_smb_length(int fd,char *inbuf,int timeout)
+static int read_smb_length_return_keepalive(int fd,char *inbuf,int timeout)
 {
-  char *buffer;
-  char buf[4];
   int len=0, msg_type;
   BOOL ok=False;
 
-  if (inbuf)
-    buffer = inbuf;
-  else
-    buffer = buf;
-
   while (!ok)
     {
       if (timeout > 0)
-       ok = (read_with_timeout(fd,buffer,4,4,timeout) == 4);
+       ok = (read_with_timeout(fd,inbuf,4,4,timeout) == 4);
       else 
-       ok = (read_data(fd,buffer,4) == 4);
+       ok = (read_data(fd,inbuf,4) == 4);
 
       if (!ok)
        return(-1);
 
-      len = smb_len(buffer);
-      msg_type = CVAL(buffer,0);
+      len = smb_len(inbuf);
+      msg_type = CVAL(inbuf,0);
 
       if (msg_type == 0x85) 
-       {
-         DEBUG(5,("Got keepalive packet\n"));
-         ok = False;
-       }
+        DEBUG(5,("Got keepalive packet\n"));
     }
 
   DEBUG(10,("got smb length of %d\n",len));
@@ -2267,13 +2438,39 @@ int read_smb_length(int fd,char *inbuf,int timeout)
   return(len);
 }
 
+/****************************************************************************
+read 4 bytes of a smb packet and return the smb length of the packet
+store the result in the buffer. This version of the function will
+never return a session keepalive (length of zero).
+****************************************************************************/
+int read_smb_length(int fd,char *inbuf,int timeout)
+{
+  int len;
+
+  for(;;)
+  {
+    len = read_smb_length_return_keepalive(fd, inbuf, timeout);
+
+    if(len < 0)
+      return len;
+
+    /* Ignore session keepalives. */
+    if(CVAL(inbuf,0) != 0x85)
+      break;
+  }
 
+  return len;
+}
 
 /****************************************************************************
-  read an smb from a fd.
-The timeout is in milli seconds
+  read an smb from a fd. Note that the buffer *MUST* be of size
+  BUFFER_SIZE+SAFETY_MARGIN.
+  The timeout is in milli seconds. 
+
+  This function will return on a
+  receipt of a session keepalive packet.
 ****************************************************************************/
-BOOL receive_smb(int fd,char *buffer,int timeout)
+BOOL receive_smb(int fd,char *buffer, int timeout)
 {
   int len,ret;
 
@@ -2281,8 +2478,8 @@ BOOL receive_smb(int fd,char *buffer,int timeout)
 
   bzero(buffer,smb_size + 100);
 
-  len = read_smb_length(fd,buffer,timeout);
-  if (len == -1)
+  len = read_smb_length_return_keepalive(fd,buffer,timeout);
+  if (len < 0)
     return(False);
 
   if (len > BUFFER_SIZE) {
@@ -2291,38 +2488,232 @@ BOOL receive_smb(int fd,char *buffer,int timeout)
       exit(1);
   }
 
-  ret = read_data(fd,buffer+4,len);
-  if (ret != len) {
-    smb_read_error = READ_ERROR;
-    return False;
+  if(len > 0) {
+    ret = read_data(fd,buffer+4,len);
+    if (ret != len) {
+      smb_read_error = READ_ERROR;
+      return False;
+    }
   }
-
   return(True);
 }
 
-#ifdef USE_OPLOCKS
 /****************************************************************************
-  Do a select on an two fd's - with timeout. 
+  read an smb from a fd ignoring all keepalive packets. Note that the buffer 
+  *MUST* be of size BUFFER_SIZE+SAFETY_MARGIN.
+  The timeout is in milli seconds
+
+  This is exactly the same as receive_smb except that it never returns
+  a session keepalive packet (just as receive_smb used to do).
+  receive_smb was changed to return keepalives as the oplock processing means this call
+  should never go into a blocking read.
+****************************************************************************/
 
-  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.
+BOOL client_receive_smb(int fd,char *buffer, int timeout)
+{
+  BOOL ret;
+
+  for(;;)
+  {
+    ret = receive_smb(fd, buffer, timeout);
+
+    if(ret == False)
+      return ret;
+
+    /* Ignore session keepalive packets. */
+    if(CVAL(buffer,0) != 0x85)
+      break;
+  }
+  return ret;
+}
 
+/****************************************************************************
+  read a message from a udp fd.
 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)
+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;
+
+  smb_read_error = 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 messages.
+ for processing.
+****************************************************************************/
+
+typedef struct _message_list {
+   struct _message_list *msg_next;
+   char *msg_buf;
+   int msg_len;
+} pending_message_list;
+
+static pending_message_list *smb_msg_head = NULL;
+
+/****************************************************************************
+ Function to push a linked list of local messages ready
+ for processing.
+****************************************************************************/
+
+static BOOL push_local_message(pending_message_list **pml, char *buf, int msg_len)
+{
+  pending_message_list *msg = (pending_message_list *)
+                               malloc(sizeof(pending_message_list));
+
+  if(msg == NULL)
+  {
+    DEBUG(0,("push_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 = *pml;
+  *pml = msg;
+
+  return True;
+}
+
+/****************************************************************************
+ Function to push a linked list of local smb messages ready
+ for processing.
+****************************************************************************/
+
+BOOL push_smb_message(char *buf, int msg_len)
+{
+  return push_local_message(&smb_msg_head, buf, msg_len);
+}
+
+/****************************************************************************
+  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 a pending smb message has been pushed onto the
+  queue (this can only happen during oplock break
+  processing) return this next.
+
+  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;
 
+  smb_read_error = 0;
+
   *got_smb = False;
+
+  /*
+   * Check to see if we already have a message on the smb queue.
+   * If so - copy and return it.
+   */
+  
+  if(smb_msg_head)
+  {
+    pending_message_list *msg = smb_msg_head;
+    memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len));
+    smb_msg_head = msg->msg_next;
+  
+    /* Free the message we just copied. */
+    free((char *)msg->msg_buf);
+    free((char *)msg);
+    *got_smb = True;
+
+    DEBUG(5,("receive_message_or_smb: returning queued smb message.\n"));
+    return True;
+  }
+
   FD_ZERO(&fds);
   FD_SET(smbfd,&fds);
   FD_SET(oplock_fd,&fds);
@@ -2352,36 +2743,9 @@ BOOL receive_message_or_smb(int smbfd, int oplock_fd,
   }
   else
   {
-    /*
-     * Read a udp message.
-     */
-    struct sockaddr_in from;
-    int fromlen = sizeof(from);
-    int32 msg_len = 0;
-    uint16 port = 0;
-
-    msg_len = recvfrom(oplock_fd, &buffer[6+sizeof(struct in_addr)],
-              buffer_len - (6 + sizeof(struct in_addr)), 0,
-              (struct sockaddr *)&from, &fromlen);
-
-    if(msg_len < 0)
-    {
-      DEBUG(0,("Invalid loopback packet ! (%s).\n",strerror(errno)));
-      return False;
-    }
-
-    port = ntohs(from.sin_port);
-
-    /* Setup the message header */
-    SIVAL(buffer,0,msg_len);
-    SSVAL(buffer,4,port);
-    memcpy(&buffer[6],(char *)&from.sin_addr,sizeof(struct in_addr));
-
+    return receive_local_message(oplock_fd, buffer, buffer_len, 0);
   }
-
-  return True;
 }
-#endif /* USE_OPLOCKS */
 
 /****************************************************************************
   send an smb to a fd 
@@ -2437,24 +2801,30 @@ int name_extract(char *buf,int ofs,char *name)
 {
   char *p = name_ptr(buf,ofs);
   int d = PTR_DIFF(p,buf+ofs);
-  strcpy(name,"");
+  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 *s)
-{
-  char *s0=s;
-  unsigned char c = *(unsigned char *)s;
-  if ((c & 0xC0) == 0xC0)
+int name_len( char *s )
+  {
+  int len;
+
+  /* If the two high bits of the byte are set, return 2. */
+  if( 0xC0 == (*(unsigned char *)s & 0xC0) )
     return(2);
-  while (*s) s += (*s)+1;
-  return(PTR_DIFF(s,s0)+1);
-}
+
+  /* Add up the length bytes. */
+  for( len = 1; (*s); s += (*s) + 1 )
+    {
+    len += *s + 1;
+    }
+
+  return( len );
+  } /* name_len */
 
 /****************************************************************************
 send a single packet to a port on another machine
@@ -2569,8 +2939,13 @@ BOOL string_init(char **dest,char *src)
     }
   else
     {
-      *dest = (char *)malloc(l+1);
-      strcpy(*dest,src);
+      (*dest) = (char *)malloc(l+1);
+      if ((*dest) == NULL) {
+             DEBUG(0,("Out of memory in string_init\n"));
+             return False;
+      }
+
+      pstrcpy(*dest,src);
     }
   return(True);
 }
@@ -2632,12 +3007,12 @@ BOOL string_sub(char *s,char *pattern,char *insert)
   return(ret);
 }
 
-
-
 /*********************************************************
 * Recursive routine that is called by mask_match.
-* Does the actual matching.
+* Does the actual matching. Returns True if matched,
+* False if failed.
 *********************************************************/
+
 BOOL do_match(char *str, char *regexp, int case_sig)
 {
   char *p;
@@ -2650,48 +3025,61 @@ BOOL do_match(char *str, char *regexp, int case_sig)
 
     case '*':
       /* Look for a character matching 
-        the one after the '*' */
+         the one after the '*' */
       p++;
       if(!*p)
-       return True; /* Automatic match */
+        return True; /* Automatic match */
       while(*str) {
-       while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str))))
-         str++;
-       if(do_match(str,p,case_sig))
-         return True;
-       if(!*str)
-         return False;
-       else
-         str++;
+        while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str))))
+          str++;
+        /* Now eat all characters that match, as
+           we want the *last* character to match. */
+        while(*str && (case_sig ? (*p == *str) : (toupper(*p)==toupper(*str))))
+          str++;
+        str--; /* We've eaten the match char after the '*' */
+        if(do_match(str,p,case_sig)) {
+          return True;
+        }
+        if(!*str) {
+          return False;
+        } else {
+          str++;
+        }
       }
       return False;
 
     default:
       if(case_sig) {
-       if(*str != *p)
-         return False;
+        if(*str != *p) {
+          return False;
+        }
       } else {
-       if(toupper(*str) != toupper(*p))
-         return False;
+        if(toupper(*str) != toupper(*p)) {
+          return False;
+        }
       }
       str++, p++;
       break;
     }
   }
+
   if(!*p && !*str)
     return True;
 
-  if (!*p && str[0] == '.' && str[1] == 0)
+  if (!*p && str[0] == '.' && str[1] == 0) {
     return(True);
+  }
   
-  if (!*str && *p == '?')
-    {
-      while (*p == '?') p++;
-      return(!*p);
-    }
+  if (!*str && *p == '?') {
+    while (*p == '?')
+      p++;
+    return(!*p);
+  }
 
-  if(!*str && (*p == '*' && p[1] == '\0'))
+  if(!*str && (*p == '*' && p[1] == '\0')) {
     return True;
+  }
   return False;
 }
 
@@ -2700,106 +3088,239 @@ BOOL do_match(char *str, char *regexp, int case_sig)
 * Routine to match a given string with a regexp - uses
 * simplified regexp that takes * and ? only. Case can be
 * significant or not.
+* The 8.3 handling was rewritten by Ums Harald <Harald.Ums@pro-sieben.de>
 *********************************************************/
+
 BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
 {
   char *p;
-  pstring p1, p2;
+  pstring t_pattern, t_filename, te_pattern, te_filename;
   fstring ebase,eext,sbase,sext;
 
-  BOOL matched;
+  BOOL matched = False;
 
   /* Make local copies of str and regexp */
-  StrnCpy(p1,regexp,sizeof(pstring)-1);
-  StrnCpy(p2,str,sizeof(pstring)-1);
-
-  if (!strchr(p2,'.')) {
-    strcat(p2,".");
-  }
+  pstrcpy(t_pattern,regexp);
+  pstrcpy(t_filename,str);
 
-/*
-  if (!strchr(p1,'.')) {
-    strcat(p1,".");
-  }
-*/
+#if 0
+  /* 
+   * Not sure if this is a good idea. JRA.
+   */
+  if(trans2 && is_8_3(t_pattern,False) && is_8_3(t_filename,False))
+    trans2 = False;
+#endif
 
 #if 0
-  if (strchr(p1,'.'))
-    {
-      string_sub(p1,"*.*","*");
-      string_sub(p1,".*","*");
-    }
+  if (!strchr(t_filename,'.')) {
+    pstrcat(t_filename,".");
+  }
 #endif
 
   /* Remove any *? and ** as they are meaningless */
-  for(p = p1; *p; p++)
-    while( *p == '*' && (p[1] == '?' ||p[1] == '*'))
-      (void)strcpy( &p[1], &p[2]);
+  string_sub(t_pattern, "*?", "*");
+  string_sub(t_pattern, "**", "*");
 
-  if (strequal(p1,"*")) return(True);
+  if (strequal(t_pattern,"*"))
+    return(True);
+
+  DEBUG(8,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", t_filename, t_pattern, case_sig));
+
+  if(trans2) {
+    /*
+     * Match each component of the regexp, split up by '.'
+     * characters.
+     */
+    char *fp, *rp, *cp2, *cp1;
+    BOOL last_wcard_was_star = False;
+    int num_path_components, num_regexp_components;
 
-  DEBUG(5,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
+    pstrcpy(te_pattern,t_pattern);
+    pstrcpy(te_filename,t_filename);
+    /*
+     * Remove multiple "*." patterns.
+     */
+    string_sub(te_pattern, "*.*.", "*.");
+    num_regexp_components = count_chars(te_pattern, '.');
+    num_path_components = count_chars(te_filename, '.');
 
-  if (trans2) {
-    strcpy(ebase,p1);
-    strcpy(sbase,p2);
+    /* 
+     * Check for special 'hack' case of "DIR a*z". - needs to match a.b.c...z
+     */
+    if(num_regexp_components == 0)
+      matched = do_match( te_filename, te_pattern, case_sig);
+    else {
+      for( cp1 = te_pattern, cp2 = te_filename; cp1;) {
+        fp = strchr(cp2, '.');
+        if(fp)
+          *fp = '\0';
+        rp = strchr(cp1, '.');
+        if(rp)
+          *rp = '\0';
+
+        if(cp1[strlen(cp1)-1] == '*')
+          last_wcard_was_star = True;
+        else
+          last_wcard_was_star = False;
+
+        if(!do_match(cp2, cp1, case_sig))
+          break;
+
+        cp1 = rp ? rp + 1 : NULL;
+        cp2 = fp ? fp + 1 : "";
+
+        if(last_wcard_was_star || ((cp1 != NULL) && (*cp1 == '*'))) {
+          /* Eat the extra path components. */
+          int i;
+
+          for(i = 0; i < num_path_components - num_regexp_components; i++) {
+            fp = strchr(cp2, '.');
+            if(fp)
+              *fp = '\0';
+
+            if((cp1 != NULL) && do_match( cp2, cp1, case_sig)) {
+              cp2 = fp ? fp + 1 : "";
+              break;
+            }
+            cp2 = fp ? fp + 1 : "";
+          }
+          num_path_components -= i;
+        }
+      } 
+      if(cp1 == NULL && ((*cp2 == '\0') || last_wcard_was_star))
+        matched = True;
+    }
   } else {
-    if ((p=strrchr(p1,'.'))) {
-      *p = 0;
-      strcpy(ebase,p1);
-      strcpy(eext,p+1);
+
+    /* -------------------------------------------------
+     * Behaviour of Win95
+     * for 8.3 filenames and 8.3 Wildcards
+     * -------------------------------------------------
+     */
+    if (strequal (t_filename, ".")) {
+      /*
+       *  Patterns:  *.*  *. ?. ?  are valid
+       *
+       */
+      if(strequal(t_pattern, "*.*") || strequal(t_pattern, "*.") ||
+         strequal(t_pattern, "?.") || strequal(t_pattern, "?"))
+        matched = True;
+    } else if (strequal (t_filename, "..")) {
+      /*
+       *  Patterns:  *.*  *. ?. ? *.? are valid
+       *
+       */
+      if(strequal(t_pattern, "*.*") || strequal(t_pattern, "*.") ||
+         strequal(t_pattern, "?.") || strequal(t_pattern, "?") ||
+         strequal(t_pattern, "*.?") || strequal(t_pattern, "?.*"))
+        matched = True;
     } else {
-      strcpy(ebase,p1);
-      eext[0] = 0;
-    }
 
-  if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) {
-    *p = 0;
-    strcpy(sbase,p2);
-    strcpy(sext,p+1);
-  } else {
-    strcpy(sbase,p2);
-    strcpy(sext,"");
-  }
-  }
+      if ((p = strrchr (t_pattern, '.'))) {
+        /*
+         * Wildcard has a suffix.
+         */
+        *p = 0;
+        fstrcpy (ebase, t_pattern);
+        if (p[1]) {
+          fstrcpy (eext, p + 1);
+        } else {
+          /* pattern ends in DOT: treat as if there is no DOT */
+          *eext = 0;
+          if (strequal (ebase, "*"))
+            return (True);
+        }
+      } else {
+        /*
+         * No suffix for wildcard.
+         */
+        fstrcpy (ebase, t_pattern);
+        eext[0] = 0;
+      }
+
+      p = strrchr (t_filename, '.');
+      if (p && (p[1] == 0)     ) {
+        /*
+         * Filename has an extension of '.' only.
+         */
+        *p = 0; /* nuke dot at end of string */
+        p = 0;  /* and treat it as if there is no extension */
+      }
 
-  matched = do_match(sbase,ebase,case_sig) && 
-    (trans2 || do_match(sext,eext,case_sig));
+      if (p) {
+        /*
+         * Filename has an extension.
+         */
+        *p = 0;
+        fstrcpy (sbase, t_filename);
+        fstrcpy (sext, p + 1);
+        if (*eext) {
+          matched = do_match(sbase, ebase, case_sig)
+                    && do_match(sext, eext, case_sig);
+        } else {
+          /* pattern has no extension */
+          /* Really: match complete filename with pattern ??? means exactly 3 chars */
+          matched = do_match(str, ebase, case_sig);
+        }
+      } else {
+        /* 
+         * Filename has no extension.
+         */
+        fstrcpy (sbase, t_filename);
+        fstrcpy (sext, "");
+        if (*eext) {
+          /* pattern has extension */
+          matched = do_match(sbase, ebase, case_sig)
+                    && do_match(sext, eext, case_sig);
+        } else {
+          matched = do_match(sbase, ebase, case_sig);
+#ifdef EMULATE_WEIRD_W95_MATCHING
+          /*
+           * Even Microsoft has some problems
+           * Behaviour Win95 -> local disk 
+           * is different from Win95 -> smb drive from Nt 4.0
+           * This branch would reflect the Win95 local disk behaviour
+           */
+          if (!matched) {
+            /* a? matches aa and a in w95 */
+            fstrcat (sbase, ".");
+            matched = do_match(sbase, ebase, case_sig);
+          }
+#endif
+        }
+      }
+    }
+  }
 
-  DEBUG(5,("mask_match returning %d\n", matched));
+  DEBUG(8,("mask_match returning %d\n", matched));
 
   return matched;
 }
 
-
-
 /****************************************************************************
 become a daemon, discarding the controlling terminal
 ****************************************************************************/
 void become_daemon(void)
 {
-#ifndef NO_FORK_DEBUG
-  if (fork())
-    exit(0);
+       if (fork()) {
+               _exit(0);
+       }
 
   /* detach from the terminal */
-#ifdef USE_SETSID
-  setsid();
-#else /* USE_SETSID */
-#ifdef TIOCNOTTY
-  {
-    int i = open("/dev/tty", O_RDWR);
-    if (i >= 0) 
-      {
-       ioctl(i, (int) TIOCNOTTY, (char *)0);      
-       close(i);
-      }
-  }
-#endif /* TIOCNOTTY */
-#endif /* USE_SETSID */
-  /* Close fd's 0,1,2. Needed if started by rsh */
-  close_low_fds();
-#endif /* NO_FORK_DEBUG */
+#ifdef HAVE_SETSID
+       setsid();
+#elif defined(TIOCNOTTY)
+       {
+               int i = open("/dev/tty", O_RDWR);
+               if (i != -1) {
+                       ioctl(i, (int) TIOCNOTTY, (char *)0);      
+                       close(i);
+               }
+       }
+#endif /* HAVE_SETSID */
+
+       /* Close fd's 0,1,2. Needed if started by rsh */
+       close_low_fds();
 }
 
 
@@ -2898,7 +3419,7 @@ int set_filelen(int fd, long len)
    extend a file with ftruncate. Provide alternate implementation
    for this */
 
-#if FTRUNCATE_CAN_EXTEND
+#ifdef HAVE_FTRUNCATE_EXTEND
   return ftruncate(fd, len);
 #else
   struct stat st;
@@ -2967,11 +3488,11 @@ char *dirname_dos(char *path,char *buf)
   char *p = strrchr(path,'\\');
 
   if (!p)
-    strcpy(buf,path);
+    pstrcpy(buf,path);
   else
     {
       *p = 0;
-      strcpy(buf,path);
+      pstrcpy(buf,path);
       *p = '\\';
     }
 
@@ -2987,9 +3508,9 @@ static char *filename_dos(char *path,char *buf)
   char *p = strrchr(path,'\\');
 
   if (!p)
-    strcpy(buf,path);
+    pstrcpy(buf,path);
   else
-    strcpy(buf,p+1);
+    pstrcpy(buf,p+1);
 
   return(buf);
 }
@@ -3020,21 +3541,6 @@ void *Realloc(void *p,int size)
   return(ret);
 }
 
-#ifdef NOSTRDUP
-/****************************************************************************
-duplicate a string
-****************************************************************************/
- char *strdup(char *s)
-{
-  char *ret = NULL;
-  if (!s) return(NULL);
-  ret = (char *)malloc(strlen(s)+1);
-  if (!ret) return(NULL);
-  strcpy(ret,s);
-  return(ret);
-}
-#endif
-
 
 /****************************************************************************
   Signal handler for SIGPIPE (write on a disconnected socket) 
@@ -3065,7 +3571,7 @@ BOOL get_myname(char *my_name,struct in_addr *ip)
   /* get host info */
   if ((hp = Get_Hostbyname(hostname)) == 0) 
     {
-      DEBUG(0,( "Get_Hostbyname: Unknown host %s.\n",hostname));
+      DEBUG(0,( "Get_Hostbyname: Unknown host %s\n",hostname));
       return False;
     }
 
@@ -3075,7 +3581,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)
@@ -3114,13 +3620,14 @@ int open_socket_in(int type, int port, int dlevel,uint32 socket_addr)
   /* get host info */
   if ((hp = Get_Hostbyname(host_name)) == 0) 
     {
-      DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",host_name));
+      DEBUG(0,( "Get_Hostbyname: Unknown host %s\n",host_name));
       return -1;
     }
   
   bzero((char *)&sock,sizeof(sock));
   memcpy((char *)&sock.sin_addr,(char *)hp->h_addr, hp->h_length);
-#if defined(__FreeBSD__) || defined(NETBSD) /* XXX not the right ifdef */
+
+#ifdef HAVE_SOCK_SIN_LEN
   sock.sin_len = sizeof(sock);
 #endif
   sock.sin_port = htons( port );
@@ -3140,8 +3647,8 @@ int open_socket_in(int type, int port, int dlevel,uint32 socket_addr)
     { 
       if (port) {
        if (port == SMB_PORT || port == NMB_PORT)
-         DEBUG(dlevel,("bind failed on port %d socket_addr=%x (%s)\n",
-                       port,socket_addr,strerror(errno))); 
+         DEBUG(dlevel,("bind failed on port %d socket_addr=%s (%s)\n",
+                       port,inet_ntoa(sock.sin_addr),strerror(errno))); 
        close(res); 
 
        if (dlevel > 0 && port < 1000)
@@ -3215,6 +3722,7 @@ connect_again:
   if (ret < 0) {
     DEBUG(1,("error connecting to %s:%d (%s)\n",
             inet_ntoa(*addr),port,strerror(errno)));
+    close(res);
     return -1;
   }
 
@@ -3293,6 +3801,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);
   }
 
@@ -3377,129 +3889,414 @@ static BOOL matchname(char *remotehost,struct in_addr  addr)
 static BOOL global_client_name_done = False;
 static BOOL global_client_addr_done = False;
 
-void reset_globals_after_fork()
+void reset_globals_after_fork(void)
 {
   global_client_name_done = False;
   global_client_addr_done = False;
+
+  /*
+   * Re-seed the random crypto generator, so all smbd's
+   * started from the same parent won't generate the same
+   * sequence.
+   */
+  {
+    unsigned char dummy;
+    generate_random_buffer( &dummy, 1, True);
+  } 
 }
  
 /*******************************************************************
  return the DNS name of the client 
  ******************************************************************/
-char *client_name(void)
+char *client_name(int fd)
 {
-  extern int Client;
-  struct sockaddr sa;
-  struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
-  int     length = sizeof(sa);
-  static pstring name_buf;
-  struct hostent *hp;
-
-  if (global_client_name_done) 
-    return name_buf;
-
-  strcpy(name_buf,"UNKNOWN");
-
-  if (getpeername(Client, &sa, &length) < 0) {
-    DEBUG(0,("getpeername failed\n"));
-    return name_buf;
-  }
-
-  /* Look up the remote host name. */
-  if ((hp = gethostbyaddr((char *) &sockin->sin_addr,
-                         sizeof(sockin->sin_addr),
-                         AF_INET)) == 0) {
-    DEBUG(1,("Gethostbyaddr failed for %s\n",client_addr()));
-    StrnCpy(name_buf,client_addr(),sizeof(name_buf) - 1);
-  } else {
-    StrnCpy(name_buf,(char *)hp->h_name,sizeof(name_buf) - 1);
-    if (!matchname(name_buf, sockin->sin_addr)) {
-      DEBUG(0,("Matchname failed on %s %s\n",name_buf,client_addr()));
-      strcpy(name_buf,"UNKNOWN");
-    }
-  }
-  global_client_name_done = True;
-  return name_buf;
+       struct sockaddr sa;
+       struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
+       int     length = sizeof(sa);
+       static pstring name_buf;
+       struct hostent *hp;
+       static int last_fd=-1;
+       
+       if (global_client_name_done && last_fd == fd) 
+               return name_buf;
+       
+       last_fd = fd;
+       global_client_name_done = False;
+       
+       pstrcpy(name_buf,"UNKNOWN");
+       
+       if (fd == -1) {
+               return name_buf;
+       }
+       
+       if (getpeername(fd, &sa, &length) < 0) {
+               DEBUG(0,("getpeername failed\n"));
+               return name_buf;
+       }
+       
+       /* Look up the remote host name. */
+       if ((hp = gethostbyaddr((char *) &sockin->sin_addr,
+                               sizeof(sockin->sin_addr),
+                               AF_INET)) == 0) {
+               DEBUG(1,("Gethostbyaddr failed for %s\n",client_addr(fd)));
+               StrnCpy(name_buf,client_addr(fd),sizeof(name_buf) - 1);
+       } else {
+               StrnCpy(name_buf,(char *)hp->h_name,sizeof(name_buf) - 1);
+               if (!matchname(name_buf, sockin->sin_addr)) {
+                       DEBUG(0,("Matchname failed on %s %s\n",name_buf,client_addr(fd)));
+                       pstrcpy(name_buf,"UNKNOWN");
+               }
+       }
+       global_client_name_done = True;
+       return name_buf;
 }
 
 /*******************************************************************
  return the IP addr of the client as a string 
  ******************************************************************/
-char *client_addr(void)
+char *client_addr(int fd)
 {
-  extern int Client;
-  struct sockaddr sa;
-  struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
-  int     length = sizeof(sa);
-  static fstring addr_buf;
+       struct sockaddr sa;
+       struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
+       int     length = sizeof(sa);
+       static fstring addr_buf;
+       static int last_fd = -1;
 
-  if (global_client_addr_done
-    return addr_buf;
+       if (global_client_addr_done && fd == last_fd
+               return addr_buf;
 
-  strcpy(addr_buf,"0.0.0.0");
-
-  if (getpeername(Client, &sa, &length) < 0) {
-    DEBUG(0,("getpeername failed\n"));
-    return addr_buf;
-  }
+       last_fd = fd;
+       global_client_addr_done = False;
 
-  strcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
+       fstrcpy(addr_buf,"0.0.0.0");
 
-  global_client_addr_done = True;
-  return addr_buf;
+       if (fd == -1) {
+               return addr_buf;
+       }
+       
+       if (getpeername(fd, &sa, &length) < 0) {
+               DEBUG(0,("getpeername failed\n"));
+               return addr_buf;
+       }
+       
+       fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
+       
+       global_client_addr_done = True;
+       return addr_buf;
 }
 
-/*******************************************************************
-sub strings with useful parameters
-Rewritten by Stefaan A Eeckels <Stefaan.Eeckels@ecc.lu> and
-Paul Rippin <pr3245@nopc.eurostat.cec.be>
-********************************************************************/
-void standard_sub_basic(char *str)
-  {
-  char *s, *p;
-    char pidstr[10];
-  struct passwd *pass;
+#if (defined(HAVE_NETGROUP) && defined(WITH_AUTOMOUNT))
+/******************************************************************
+ Remove any mount options such as -rsize=2048,wsize=2048 etc.
+ Based on a fix from <Thomas.Hepper@icem.de>.
+*******************************************************************/
 
-  for (s = str ; (p = strchr(s,'%')) != NULL ; s = p )
-  {
-    switch (*(p+1))
-  {
-      case 'G' : if ((pass = Get_Pwnam(sesssetup_user,False))!=NULL)
-                   string_sub(p,"%G",gidtoname(pass->pw_gid));
-                 else
-                   p += 2;
-                 break;
-      case 'I' : string_sub(p,"%I",client_addr()); break;
-      case 'L' : string_sub(p,"%L",local_machine); break;
-      case 'M' : string_sub(p,"%M",client_name()); break;
-      case 'R' : string_sub(p,"%R",remote_proto); break;
-      case 'T' : string_sub(p,"%T",timestring()); break;
-      case 'U' : string_sub(p,"%U",sesssetup_user); break;
-      case 'a' : string_sub(p,"%a",remote_arch); break;
-      case 'd' : sprintf(pidstr,"%d",(int)getpid());
-                 string_sub(p,"%d",pidstr);
-                 break;
-      case 'h' : string_sub(p,"%h",myhostname); break;
-      case 'm' : string_sub(p,"%m",remote_machine); break;
-      case 'v' : string_sub(p,"%v",VERSION); break;
-      case '\0' : p++; break; /* don't run off end if last character is % */
-      default  : p+=2; break;
+static void strip_mount_options( pstring *str)
+{
+  if (**str == '-')
+  { 
+    char *p = *str;
+    while(*p && !isspace(*p))
+      p++;
+    while(*p && isspace(*p))
+      p++;
+    if(*p) {
+      pstring tmp_str;
+
+      pstrcpy(tmp_str, p);
+      pstrcpy(*str, tmp_str);
     }
   }
-  return;
 }
 
 /*******************************************************************
-are two IPs on the same subnet?
-********************************************************************/
-BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask)
+ Patch from jkf@soton.ac.uk
+ Split Luke's automount_server into YP lookup and string splitter
+ so can easily implement automount_path(). 
+ As we may end up doing both, cache the last YP result. 
+*******************************************************************/
+
+#ifdef NISPLUS_HOME
+static char *automount_lookup(char *user_name)
 {
-  uint32 net1,net2,nmask;
-
-  nmask = ntohl(mask.s_addr);
-  net1  = ntohl(ip1.s_addr);
-  net2  = ntohl(ip2.s_addr);
-            
+  static fstring last_key = "";
+  static pstring last_value = "";
+  char *nis_map = (char *)lp_nis_home_map_name();
+  char nis_domain[NIS_MAXNAMELEN + 1];
+  char buffer[NIS_MAXATTRVAL + 1];
+  nis_result *result;
+  nis_object *object;
+  entry_obj  *entry;
+  strncpy(nis_domain, (char *)nis_local_directory(), NIS_MAXNAMELEN);
+  nis_domain[NIS_MAXNAMELEN] = '\0';
+  DEBUG(5, ("NIS+ Domain: %s\n", nis_domain));
+  if (strcmp(user_name, last_key))
+  {
+    slprintf(buffer, sizeof(buffer)-1, "[%s=%s]%s.%s", "key", user_name, nis_map, nis_domain);
+    DEBUG(5, ("NIS+ querystring: %s\n", buffer));
+    if (result = nis_list(buffer, RETURN_RESULT, NULL, NULL))
+    {
+       if (result->status != NIS_SUCCESS)
+      {
+        DEBUG(3, ("NIS+ query failed: %s\n", nis_sperrno(result->status)));
+        fstrcpy(last_key, ""); pstrcpy(last_value, "");
+      }
+      else
+      {
+        object = result->objects.objects_val;
+        if (object->zo_data.zo_type == ENTRY_OBJ)
+        {
+           entry = &object->zo_data.objdata_u.en_data;
+           DEBUG(5, ("NIS+ entry type: %s\n", entry->en_type));
+           DEBUG(3, ("NIS+ result: %s\n", entry->en_cols.en_cols_val[1].ec_value.ec_value_val));
+           pstrcpy(last_value, entry->en_cols.en_cols_val[1].ec_value.ec_value_val);
+           string_sub(last_value, "&", user_name);
+           fstrcpy(last_key, user_name);
+        }
+      }
+    }
+    nis_freeresult(result);
+  }
+
+  strip_mount_options(&last_value);
+
+  DEBUG(4, ("NIS+ Lookup: %s resulted in %s\n", user_name, last_value));
+  return last_value;
+}
+#else /* NISPLUS_HOME */
+static char *automount_lookup(char *user_name)
+{
+  static fstring last_key = "";
+  static pstring last_value = "";
+
+  int nis_error;        /* returned by yp all functions */
+  char *nis_result;     /* yp_match inits this */
+  int nis_result_len;  /* and set this */
+  char *nis_domain;     /* yp_get_default_domain inits this */
+  char *nis_map = (char *)lp_nis_home_map_name();
+
+  if ((nis_error = yp_get_default_domain(&nis_domain)) != 0)
+  {
+    DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error)));
+    return last_value;
+  }
+
+  DEBUG(5, ("NIS Domain: %s\n", nis_domain));
+
+  if (!strcmp(user_name, last_key))
+  {
+    nis_result = last_value;
+    nis_result_len = strlen(last_value);
+    nis_error = 0;
+  }
+  else
+  {
+    if ((nis_error = yp_match(nis_domain, nis_map,
+                              user_name, strlen(user_name),
+                              &nis_result, &nis_result_len)) != 0)
+    {
+      DEBUG(3, ("YP Error: \"%s\" while looking up \"%s\" in map \"%s\"\n", 
+               yperr_string(nis_error), user_name, nis_map));
+    }
+    if (!nis_error && nis_result_len >= sizeof(pstring))
+    {
+      nis_result_len = sizeof(pstring)-1;
+    }
+    fstrcpy(last_key, user_name);
+    strncpy(last_value, nis_result, nis_result_len);
+    last_value[nis_result_len] = '\0';
+  }
+
+  strip_mount_options(&last_value);
+
+  DEBUG(4, ("YP Lookup: %s resulted in %s\n", user_name, last_value));
+  return last_value;
+}
+#endif /* NISPLUS_HOME */
+#endif
+
+/*******************************************************************
+ Patch from jkf@soton.ac.uk
+ This is Luke's original function with the NIS lookup code
+ moved out to a separate function.
+*******************************************************************/
+
+char *automount_server(char *user_name)
+{
+       static pstring server_name;
+
+       /* use the local machine name as the default */
+       /* this will be the default if WITH_AUTOMOUNT is not used or fails */
+       pstrcpy(server_name, local_machine);
+
+#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
+
+       if (lp_nis_home_map())
+       {
+               int home_server_len;
+               char *automount_value = automount_lookup(user_name);
+               home_server_len = strcspn(automount_value,":");
+               DEBUG(5, ("NIS lookup succeeded.  Home server length: %d\n",home_server_len));
+               if (home_server_len > sizeof(pstring))
+               {
+                       home_server_len = sizeof(pstring);
+               }
+               strncpy(server_name, automount_value, home_server_len);
+                server_name[home_server_len] = '\0';
+       }
+#endif
+
+       DEBUG(4,("Home server: %s\n", server_name));
+
+       return server_name;
+}
+
+/*******************************************************************
+ Patch from jkf@soton.ac.uk
+ Added this to implement %p (NIS auto-map version of %H)
+*******************************************************************/
+
+char *automount_path(char *user_name)
+{
+       static pstring server_path;
+
+       /* use the passwd entry as the default */
+       /* this will be the default if WITH_AUTOMOUNT is not used or fails */
+       /* pstrcpy() copes with get_home_dir() returning NULL */
+       pstrcpy(server_path, get_home_dir(user_name));
+
+#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
+
+       if (lp_nis_home_map())
+       {
+               char *home_path_start;
+               char *automount_value = automount_lookup(user_name);
+               home_path_start = strchr(automount_value,':');
+               if (home_path_start != NULL)
+               {
+                 DEBUG(5, ("NIS lookup succeeded.  Home path is: %s\n",
+                       home_path_start?(home_path_start+1):""));
+                 pstrcpy(server_path, home_path_start+1);
+               }
+       }
+#endif
+
+       DEBUG(4,("Home server path: %s\n", server_path));
+
+       return server_path;
+}
+
+
+/*******************************************************************
+sub strings with useful parameters
+Rewritten by Stefaan A Eeckels <Stefaan.Eeckels@ecc.lu> and
+Paul Rippin <pr3245@nopc.eurostat.cec.be>
+********************************************************************/
+void standard_sub_basic(char *str)
+{
+       char *s, *p;
+       char pidstr[10];
+       struct passwd *pass;
+       char *username = sam_logon_in_ssb ? samlogon_user : sesssetup_user;
+
+       for (s = str ; s && *s && (p = strchr(s,'%')); s = p )
+       {
+               switch (*(p+1))
+               {
+                       case 'G' :
+                       {
+                               if ((pass = Get_Pwnam(username,False))!=NULL)
+                               {
+                                       string_sub(p,"%G",gidtoname(pass->pw_gid));
+                               }
+                               else
+                               {
+                                       p += 2;
+                               }
+                               break;
+                       }
+                       case 'N' : string_sub(p,"%N", automount_server(username)); break;
+                       case 'I' : string_sub(p,"%I", client_addr(Client)); break;
+                       case 'L' : string_sub(p,"%L", local_machine); break;
+                       case 'M' : string_sub(p,"%M", client_name(Client)); break;
+                       case 'R' : string_sub(p,"%R", remote_proto); break;
+                       case 'T' : string_sub(p,"%T", timestring()); break;
+                       case 'U' : string_sub(p,"%U", username); break;
+                       case 'a' : string_sub(p,"%a", remote_arch); break;
+                       case 'd' :
+                       {
+                               slprintf(pidstr,sizeof(pidstr) - 1, "%d",(int)getpid());
+                               string_sub(p,"%d", pidstr);
+                               break;
+                       }
+                       case 'h' : string_sub(p,"%h", myhostname); break;
+                       case 'm' : string_sub(p,"%m", remote_machine); break;
+                       case 'v' : string_sub(p,"%v", VERSION); break;
+                       case '$' : /* Expand environment variables */
+                       {
+                               /* Contributed by Branko Cibej <branko.cibej@hermes.si> */
+                               fstring envname;
+                               char *envval;
+                               char *q, *r;
+                               int copylen;
+
+                               if (*(p+2) != '(')
+                               {
+                                       p+=2;
+                                       break;
+                               }
+                               if ((q = strchr(p,')')) == NULL)
+                               {
+                                       DEBUG(0,("standard_sub_basic: Unterminated environment \
+                                       variable [%s]\n", p));
+                                       p+=2;
+                                       break;
+                               }
+
+                               r = p+3;
+                               copylen = MIN((q-r),(sizeof(envname)-1));
+                               strncpy(envname,r,copylen);
+                               envname[copylen] = '\0';
+
+                               if ((envval = getenv(envname)) == NULL)
+                               {
+                                       DEBUG(0,("standard_sub_basic: Environment variable [%s] not set\n",
+                                       envname));
+                                       p+=2;
+                                       break;
+                               }
+
+                               copylen = MIN((q+1-p),(sizeof(envname)-1));
+                               strncpy(envname,p,copylen);
+                               envname[copylen] = '\0';
+                               string_sub(p,envname,envval);
+                               break;
+                       }
+                       case '\0': p++; break; /* don't run off end if last character is % */
+                       default  : p+=2; break;
+               }
+       }
+       return;
+}
+
+/*******************************************************************
+are two IPs on the same subnet?
+********************************************************************/
+BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask)
+{
+  uint32 net1,net2,nmask;
+
+  nmask = ntohl(mask.s_addr);
+  net1  = ntohl(ip1.s_addr);
+  net2  = ntohl(ip2.s_addr);
+            
   return((net1 & nmask) == (net2 & nmask));
 }
 
@@ -3535,11 +4332,20 @@ struct hostent *Get_Hostbyname(char *name)
       exit(0);
     }
 
+   
+  /* 
+   * This next test is redundent and causes some systems (with
+   * broken isalnum() calls) problems.
+   * JRA.
+   */
+
+#if 0
   if (!isalnum(*name2))
     {
       free(name2);
       return(NULL);
     }
+#endif /* 0 */
 
   ret = sys_gethostbyname(name2);
   if (ret != NULL)
@@ -3577,29 +4383,7 @@ check if a process exists. Does this work on all unixes?
 ****************************************************************************/
 BOOL process_exists(int pid)
 {
-#ifdef LINUX
-  fstring s;
-  sprintf(s,"/proc/%d",pid);
-  return(directory_exist(s,NULL));
-#else
-  {
-    static BOOL tested=False;
-    static BOOL ok=False;
-    fstring s;
-    if (!tested) {
-      tested = True;
-      sprintf(s,"/proc/%05d",(int)getpid());
-      ok = file_exist(s,NULL);
-    }
-    if (ok) {
-      sprintf(s,"/proc/%05d",pid);
-      return(file_exist(s,NULL));
-    }
-  }
-
-  /* CGH 8/16/96 - added ESRCH test */
-  return(pid == getpid() || kill(pid,0) == 0 || errno != ESRCH);
-#endif
+       return(kill(pid,0) == 0 || errno != ESRCH);
 }
 
 
@@ -3611,7 +4395,7 @@ char *uidtoname(int uid)
   static char name[40];
   struct passwd *pass = getpwuid(uid);
   if (pass) return(pass->pw_name);
-  sprintf(name,"%d",uid);
+  slprintf(name, sizeof(name) - 1, "%d",uid);
   return(name);
 }
 
@@ -3620,31 +4404,11 @@ turn a gid into a group name
 ********************************************************************/
 char *gidtoname(int gid)
 {
-  static char name[40];
-  struct group *grp = getgrgid(gid);
-  if (grp) return(grp->gr_name);
-  sprintf(name,"%d",gid);
-  return(name);
-}
-
-/*******************************************************************
-block sigs
-********************************************************************/
-void BlockSignals(BOOL block,int signum)
-{
-#ifdef USE_SIGBLOCK
-  int block_mask = sigmask(signum);
-  static int oldmask = 0;
-  if (block) 
-    oldmask = sigblock(block_mask);
-  else
-    sigsetmask(oldmask);
-#elif defined(USE_SIGPROCMASK)
-  sigset_t set;
-  sigemptyset(&set);
-  sigaddset(&set,signum);
-  sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL);
-#endif
+       static char name[40];
+       struct group *grp = getgrgid(gid);
+       if (grp) return(grp->gr_name);
+       slprintf(name,sizeof(name) - 1, "%d",gid);
+       return(name);
 }
 
 #if AJT
@@ -3653,15 +4417,10 @@ my own panic function - not suitable for general use
 ********************************************************************/
 void ajt_panic(void)
 {
-  system("/usr/bin/X11/xedit -display ljus:0 /tmp/ERROR_FAULT");
+       system("/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT");
 }
 #endif
 
-#ifdef USE_DIRECT
-#define DIRECT direct
-#else
-#define DIRECT dirent
-#endif
 
 /*******************************************************************
 a readdir wrapper which just returns the file name
@@ -3669,67 +4428,57 @@ also return the inode number if requested
 ********************************************************************/
 char *readdirname(void *p)
 {
-  struct DIRECT *ptr;
-  char *dname;
+       struct dirent *ptr;
+       char *dname;
 
-  if (!p) return(NULL);
+       if (!p) return(NULL);
   
-  ptr = (struct DIRECT *)readdir(p);
-  if (!ptr) return(NULL);
+       ptr = (struct dirent *)readdir(p);
+       if (!ptr) return(NULL);
 
-  dname = ptr->d_name;
+       dname = ptr->d_name;
 
 #ifdef NEXT2
-  if (telldir(p) < 0) return(NULL);
+       if (telldir(p) < 0) return(NULL);
 #endif
 
-#ifdef SUNOS5
-  /* this handles a broken compiler setup, causing a mixture
-   of BSD and SYSV headers and libraries */
-  {
-    static BOOL broken_readdir = False;
-    if (!broken_readdir && !(*(dname)) && strequal("..",dname-2))
-      {
-       DEBUG(0,("Your readdir() is broken. You have somehow mixed SYSV and BSD headers and libraries\n"));
-       broken_readdir = True;
-      }
-    if (broken_readdir)
-      dname = dname - 2;
-  }
+#ifdef HAVE_BROKEN_READDIR
+       /* using /usr/ucb/cc is BAD */
+       dname = dname - 2;
 #endif
 
-  {
-    static pstring buf;
-    strcpy(buf, dname);
-    unix_to_dos(buf, True);
-    dname = buf;
-  }
+       {
+               static pstring buf;
+               memcpy(buf, dname, NAMLEN(ptr)+1);
+               unix_to_dos(buf, True);
+               dname = buf;
+       }
 
-  return(dname);
+       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, '/');
-  strncpy(last_component, p ? p : name, sizeof(last_component)-1);
+  strncpy(last_component, p ? ++p : name, sizeof(last_component)-1);
   last_component[sizeof(last_component)-1] = '\0'; 
 
   for(; namelist->name != NULL; namelist++)
@@ -3739,7 +4488,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;
       }
     }
@@ -3748,29 +4497,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;
@@ -3911,7 +4660,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;
@@ -3959,7 +4708,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
@@ -4027,23 +4776,23 @@ void set_remote_arch(enum remote_arch_types type)
   switch( type )
   {
   case RA_WFWG:
-    strcpy(remote_arch, "WfWg");
+    fstrcpy(remote_arch, "WfWg");
     return;
   case RA_OS2:
-    strcpy(remote_arch, "OS2");
+    fstrcpy(remote_arch, "OS2");
     return;
   case RA_WIN95:
-    strcpy(remote_arch, "Win95");
+    fstrcpy(remote_arch, "Win95");
     return;
   case RA_WINNT:
-    strcpy(remote_arch, "WinNT");
+    fstrcpy(remote_arch, "WinNT");
     return;
   case RA_SAMBA:
-    strcpy(remote_arch,"Samba");
+    fstrcpy(remote_arch,"Samba");
     return;
   default:
     ra_type = RA_UNKNOWN;
-    strcpy(remote_arch, "UNKNOWN");
+    fstrcpy(remote_arch, "UNKNOWN");
     break;
   }
 }
@@ -4051,7 +4800,403 @@ void set_remote_arch(enum remote_arch_types type)
 /*******************************************************************
  Get the remote_arch type.
 ********************************************************************/
-enum remote_arch_types get_remote_arch()
+enum remote_arch_types get_remote_arch(void)
 {
   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(s) and only handles ascii strings
+********************************************************************/
+#define MAXUNI 1024
+char *unistrn2(uint16 *buf, int len)
+{
+       static char lbufs[8][MAXUNI];
+       static int nexti;
+       char *lbuf = lbufs[nexti];
+       char *p;
+
+       nexti = (nexti+1)%8;
+
+       DEBUG(10, ("unistrn2: "));
+
+       for (p = lbuf; *buf && p-lbuf < MAXUNI-2 && len > 0; len--, p++, buf++)
+       {
+               DEBUG(10, ("%4x ", *buf));
+               *p = *buf;
+       }
+
+       DEBUG(10,("\n"));
+
+       *p = 0;
+       return lbuf;
+}
+
+/*******************************************************************
+Return a ascii version of a unicode string
+Hack alert: uses fixed buffer(s) and only handles ascii strings
+********************************************************************/
+#define MAXUNI 1024
+char *unistr2(uint16 *buf)
+{
+       static char lbufs[8][MAXUNI];
+       static int nexti;
+       char *lbuf = lbufs[nexti];
+       char *p;
+
+       nexti = (nexti+1)%8;
+
+       DEBUG(10, ("unistr2: "));
+
+       for (p = lbuf; *buf && p-lbuf < MAXUNI-2; p++, buf++)
+       {
+               DEBUG(10, ("%4x ", *buf));
+               *p = *buf;
+       }
+
+       DEBUG(10,("\n"));
+
+       *p = 0;
+       return lbuf;
+}
+
+/*******************************************************************
+create a null-terminated unicode string from a null-terminated ascii string.
+return number of unicode chars copied, excluding the null character.
+
+only handles ascii strings
+********************************************************************/
+#define MAXUNI 1024
+int struni2(uint16 *p, char *buf)
+{
+       int len = 0;
+
+       if (p == NULL) return 0;
+
+       DEBUG(10, ("struni2: "));
+
+       if (buf != NULL)
+       {
+               for (; *buf && len < MAXUNI-2; len++, p++, buf++)
+               {
+                       DEBUG(10, ("%2x ", *buf));
+                       *p = *buf;
+               }
+
+               DEBUG(10,("\n"));
+       }
+
+       *p = 0;
+
+       return len;
+}
+
+/*******************************************************************
+Return a ascii version of a unicode string
+Hack alert: uses fixed buffer(s) 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 known length string. maxlength does not
+include the terminating zero.
+********************************************************************/
+char *safe_strcpy(char *dest, char *src, int maxlength)
+{
+    int len;
+
+    if (!dest) {
+        DEBUG(0,("ERROR: NULL dest in safe_strcpy\n"));
+        return NULL;
+    }
+
+    if (!src) {
+        *dest = 0;
+        return dest;
+    }  
+
+    len = strlen(src);
+
+    if (len > maxlength) {
+           DEBUG(0,("ERROR: string overflow by %d in safe_strcpy [%.50s]\n",
+                    len-maxlength, src));
+           len = maxlength;
+    }
+      
+    memcpy(dest, src, len);
+    dest[len] = 0;
+    return dest;
+}  
+
+/*******************************************************************
+safe string cat into a string. maxlength does not
+include the terminating zero.
+********************************************************************/
+char *safe_strcat(char *dest, char *src, int maxlength)
+{
+    int src_len, dest_len;
+
+    if (!dest) {
+        DEBUG(0,("ERROR: NULL dest in safe_strcat\n"));
+        return NULL;
+    }
+
+    if (!src) {
+        return dest;
+    }  
+
+    src_len = strlen(src);
+    dest_len = strlen(dest);
+
+    if (src_len + dest_len > maxlength) {
+           DEBUG(0,("ERROR: string overflow by %d in safe_strcat [%.50s]\n",
+                    src_len + dest_len - maxlength, src));
+           src_len = maxlength - dest_len;
+    }
+      
+    memcpy(&dest[dest_len], src, src_len);
+    dest[dest_len + src_len] = 0;
+    return dest;
+}
+
+/*******************************************************************
+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)
+{
+       int mod = ((q - base) & (align_offset_len-1));
+       if (align_offset_len != 0 && mod != 0)
+       {
+               q += align_offset_len - mod;
+       }
+       return q;
+}
+
+void print_asc(int level, unsigned char *buf,int len)
+{
+       int i;
+       for (i=0;i<len;i++)
+               DEBUG(level,("%c", isprint(buf[i])?buf[i]:'.'));
+}
+
+void dump_data(int level,char *buf1,int len)
+{
+  unsigned char *buf = (unsigned char *)buf1;
+  int i=0;
+  if (len<=0) return;
+
+  DEBUG(level,("[%03X] ",i));
+  for (i=0;i<len;) {
+    DEBUG(level,("%02X ",(int)buf[i]));
+    i++;
+    if (i%8 == 0) DEBUG(level,(" "));
+    if (i%16 == 0) {      
+      print_asc(level,&buf[i-16],8); DEBUG(level,(" "));
+      print_asc(level,&buf[i-8],8); DEBUG(level,("\n"));
+      if (i<len) DEBUG(level,("[%03X] ",i));
+    }
+  }
+  if (i%16) {
+    int n;
+
+    n = 16 - (i%16);
+    DEBUG(level,(" "));
+    if (n>8) DEBUG(level,(" "));
+    while (n--) DEBUG(level,("   "));
+
+    n = MIN(8,i%16);
+    print_asc(level,&buf[i-(i%16)],n); DEBUG(level,(" "));
+    n = (i%16) - n;
+    if (n>0) print_asc(level,&buf[i-n],n); 
+    DEBUG(level,("\n"));    
+  }
+}
+
+char *tab_depth(int depth)
+{
+       static pstring spaces;
+       memset(spaces, ' ', depth * 4);
+       spaces[depth * 4] = 0;
+       return spaces;
+}
+
+/*****************************************************************
+ Convert a SID to an ascii string.
+*****************************************************************/
+
+char *sid_to_string(pstring sidstr_out, DOM_SID *sid)
+{
+  char subauth[16];
+  int i;
+  /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
+  uint32 ia = (sid->id_auth[5]) +
+              (sid->id_auth[4] << 8 ) +
+              (sid->id_auth[3] << 16) +
+              (sid->id_auth[2] << 24);
+
+  slprintf(sidstr_out, sizeof(pstring) - 1, "S-%d-%d", sid->sid_rev_num, ia);
+
+  for (i = 0; i < sid->num_auths; i++)
+  {
+    slprintf(subauth, sizeof(subauth)-1, "-%d", sid->sub_auths[i]);
+    pstrcat(sidstr_out, subauth);
+  }
+
+  DEBUG(7,("sid_to_string returning %s\n", sidstr_out));
+  return sidstr_out;
+}
+
+/*****************************************************************
+ Convert a string to a SID. Returns True on success, False on fail.
+*****************************************************************/  
+   
+BOOL string_to_sid(DOM_SID *sidout, char *sidstr)
+{
+  pstring tok;
+  char *p = sidstr;
+  /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
+  uint32 ia;
+
+  memset((char *)sidout, '\0', sizeof(DOM_SID));
+
+  if(StrnCaseCmp( sidstr, "S-", 2)) {
+    DEBUG(0,("string_to_sid: Sid %s does not start with 'S-'.\n", sidstr));
+    return False;
+  }
+
+  p += 2;
+  if(!next_token(&p, tok, "-")) {
+    DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr));
+    return False;
+  }
+
+  /* Get the revision number. */
+  sidout->sid_rev_num = atoi(tok);
+
+  if(!next_token(&p, tok, "-")) {
+    DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr));
+    return False;
+  }
+
+  /* identauth in decimal should be <  2^32 */
+  ia = atoi(tok);
+
+  /* NOTE - the ia value is in big-endian format. */
+  sidout->id_auth[0] = 0;
+  sidout->id_auth[1] = 0;
+  sidout->id_auth[2] = (ia & 0xff000000) >> 24;
+  sidout->id_auth[3] = (ia & 0x00ff0000) >> 16;
+  sidout->id_auth[4] = (ia & 0x0000ff00) >> 8;
+  sidout->id_auth[5] = (ia & 0x000000ff);
+
+  sidout->num_auths = 0;
+
+  while(next_token(&p, tok, "-") && sidout->num_auths < MAXSUBAUTHS) {
+    /* 
+     * NOTE - the subauths are in native machine-endian format. They
+     * are converted to little-endian when linearized onto the wire.
+     */
+    sidout->sub_auths[sidout->num_auths++] = atoi(tok);
+  }
+
+  DEBUG(7,("string_to_sid: converted SID %s ok\n", sidstr));
+
+  return True;
+}