a pointless commit to check on a problem Luke reported with CVS
[kai/samba.git] / source3 / lib / util.c
index 8730ae3143748a8079ea5b4b3a2e6f489815b698..306e80c3073cf64b3d9e79fbba99c42ba7b0fa24 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    Samba utility functions
-   Copyright (C) Andrew Tridgell 1992-1995
+   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(NETGROUP) && defined (AUTOMOUNT))
+#include "rpcsvc/ypclnt.h"
+#endif
+
 pstring scope = "";
 
 int DEBUGLEVEL = 1;
@@ -68,17 +72,71 @@ BOOL case_mangle;
 fstring remote_machine="";
 fstring local_machine="";
 fstring remote_arch="UNKNOWN";
+static enum remote_arch_types ra_type = RA_UNKNOWN;
 fstring remote_proto="UNKNOWN";
 pstring myhostname="";
 pstring user_socket_options="";   
+
 pstring sesssetup_user="";
+pstring samlogon_user="";
+
+BOOL sam_logon_in_ssb = False;
+
 pstring myname = "";
+fstring myworkgroup = "";
+char **my_netbios_names;
 
 int smb_read_error = 0;
 
+static BOOL stdout_logging = False;
+
 static char *filename_dos(char *path,char *buf);
 
-static BOOL stdout_logging = False;
+#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);
+#ifndef DONT_REINSTALL_SIG
+  signal(SIGUSR2, SIGNAL_CAST sig_usr2);
+#endif 
+  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);
+#ifndef DONT_REINSTALL_SIG
+  signal(SIGUSR1, SIGNAL_CAST sig_usr1);
+#endif
+  return(0);
+}
+#endif /* SIGUSR1 */
 
 
 /*******************************************************************
@@ -90,7 +148,11 @@ void setup_logging(char *pname,BOOL interactive)
   if (!interactive) {
     char *p = strrchr(pname,'/');
     if (p) pname = p+1;
-    openlog(pname, LOG_PID, LOG_DAEMON);
+#ifdef LOG_DAEMON
+    openlog(pname, LOG_PID, SYSLOG_FACILITY);
+#else /* for old systems that have no facility codes. */
+    openlog(pname, LOG_PID);
+#endif
   }
 #endif
   if (interactive) {
@@ -108,7 +170,6 @@ reopen the log files
 ****************************************************************************/
 void reopen_logs(void)
 {
-  extern FILE *dbf;
   pstring fname;
   
   if (DEBUGLEVEL > 0)
@@ -150,7 +211,7 @@ static void check_log_size(void)
   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;
@@ -184,7 +245,8 @@ va_dcl
   char *format_str;
 #endif
   va_list ap;  
-  
+  int old_errno = errno;
+
   if (stdout_logging) {
 #ifdef __STDC__
     va_start(ap, format_str);
@@ -194,6 +256,7 @@ va_dcl
 #endif
     vfprintf(dbf,format_str,ap);
     va_end(ap);
+    errno = old_errno;
     return(0);
   }
   
@@ -201,16 +264,17 @@ va_dcl
   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);
+             dbf = fopen(debugf,"w");
+             umask(oldumask);
+             if (dbf) {
+                     setbuf(dbf,NULL);
+             } else {
+                     errno = old_errno;
+                     return(0);
+             }
+      }
     }
 
 #ifdef SYSLOG
@@ -267,6 +331,8 @@ va_dcl
 
   check_log_size();
 
+  errno = old_errno;
+
   return(0);
 }
 
@@ -678,48 +744,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)sprintf( buf, "%-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
@@ -754,12 +833,17 @@ time_t file_modtime(char *fname)
 BOOL directory_exist(char *dname,struct stat *st)
 {
   struct stat st2;
+  BOOL ret;
+
   if (!st) st = &st2;
 
   if (sys_stat(dname,st) != 0) 
     return(False);
 
-  return(S_ISDIR(st->st_mode));
+  ret = S_ISDIR(st->st_mode);
+  if(!ret)
+    errno = ENOTDIR;
+  return ret;
 }
 
 /*******************************************************************
@@ -798,10 +882,72 @@ char *attrib_string(int mode)
 ********************************************************************/
 int StrCaseCmp(char *s, char *t)
 {
-  for (; tolower(*s) == tolower(*t); ++s, ++t)
-    if (!*s) return 0;
+  /* compare until we run out of string, either t or s, or find a difference */
+  /* We *must* use toupper rather than tolower here due to the
+     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. */
+    int diff;
+    for (;;)
+    {
+      if (!*s || !*t)
+           return toupper (*s) - toupper (*t);
+      else if (is_sj_alph (*s) && is_sj_alph (*t))
+      {
+        diff = sj_toupper2 (*(s+1)) - sj_toupper2 (*(t+1));
+        if (diff)
+          return diff;
+        s += 2;
+        t += 2;
+      }
+      else if (is_shift_jis (*s) && is_shift_jis (*t))
+      {
+        diff = ((int) (unsigned char) *s) - ((int) (unsigned char) *t);
+        if (diff)
+          return diff;
+        diff = ((int) (unsigned char) *(s+1)) - ((int) (unsigned char) *(t+1));
+        if (diff)
+          return diff;
+        s += 2;
+        t += 2;
+      }
+      else if (is_shift_jis (*s))
+        return 1;
+      else if (is_shift_jis (*t))
+        return -1;
+      else 
+      {
+        diff = toupper (*s) - toupper (*t);
+        if (diff)
+          return diff;
+        s++;
+        t++;
+      }
+    }
+  }
+  else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+  {
+    while (*s && *t && toupper(*s) == toupper(*t))
+    {
+      s++;
+      t++;
+    }
 
-  return tolower(*s) - tolower(*t);
+    return(toupper(*s) - toupper(*t));
+  }
 }
 
 /*******************************************************************
@@ -809,19 +955,89 @@ int StrCaseCmp(char *s, char *t)
 ********************************************************************/
 int StrnCaseCmp(char *s, char *t, int n)
 {
-  while (n-- && *s && *t) {
-    if (tolower(*s) != tolower(*t)) return(tolower(*s) - tolower(*t));
-    s++; t++;
+  /* compare until we run out of string, either t or s, or chars */
+  /* We *must* use toupper rather than tolower here due to the
+     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. */
+    int diff;
+    for (;n > 0;)
+    {
+      if (!*s || !*t)
+        return toupper (*s) - toupper (*t);
+      else if (is_sj_alph (*s) && is_sj_alph (*t))
+      {
+        diff = sj_toupper2 (*(s+1)) - sj_toupper2 (*(t+1));
+        if (diff)
+          return diff;
+        s += 2;
+        t += 2;
+        n -= 2;
+      }
+      else if (is_shift_jis (*s) && is_shift_jis (*t))
+      {
+        diff = ((int) (unsigned char) *s) - ((int) (unsigned char) *t);
+        if (diff)
+          return diff;
+        diff = ((int) (unsigned char) *(s+1)) - ((int) (unsigned char) *(t+1));
+        if (diff)
+          return diff;
+        s += 2;
+        t += 2;
+        n -= 2;
+      }
+      else if (is_shift_jis (*s))
+        return 1;
+      else if (is_shift_jis (*t))
+        return -1;
+      else 
+      {
+        diff = toupper (*s) - toupper (*t);
+        if (diff)
+          return diff;
+        s++;
+        t++;
+        n--;
+      }
+    }
+    return 0;
   }
-  if (n) return(tolower(*s) - tolower(*t));
+  else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+  {
+    while (n && *s && *t && toupper(*s) == toupper(*t))
+    {
+      s++;
+      t++;
+      n--;
+    }
 
-  return(0);
+    /* not run out of chars - strings are different lengths */
+    if (n) 
+      return(toupper(*s) - toupper(*t));
+
+    /* identical up to where we run out of chars, 
+       and strings are same length */
+    return(0);
+  }
 }
 
 /*******************************************************************
   compare 2 strings 
 ********************************************************************/
-BOOL strequal(char *s1,char *s2)
+BOOL strequal(char *s1, char *s2)
 {
   if (s1 == s2) return(True);
   if (!s1 || !s2) return(False);
@@ -858,23 +1074,45 @@ BOOL strcsequal(char *s1,char *s2)
 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. */
+      if (is_shift_jis (*s))
+      {
+        if (is_sj_upper (s[0], s[1]))
+          s[1] = sj_tolower2 (s[1]);
+        s += 2;
+      }
+      else if (is_kana (*s))
+      {
+        s++;
+      }
+      else
+      {
+        if (isupper(*s))
+          *s = tolower(*s);
+        s++;
+      }
+    }
+    else
+#endif /* KANJI_WIN95_COMPATIBILITY */
     {
-#ifdef KANJI
-       if (is_shift_jis (*s)) {
-           s += 2;
-       } else if (is_kana (*s)) {
-           s++;
-       } else {
-           if (isupper(*s))
-               *s = tolower(*s);
-           s++;
-       }
-#else
       if (isupper(*s))
-         *s = tolower(*s);
+        *s = tolower(*s);
       s++;
-#endif /* KANJI */
     }
+  }
 }
 
 /*******************************************************************
@@ -883,23 +1121,45 @@ void strlower(char *s)
 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. */
+      if (is_shift_jis (*s))
+      {
+        if (is_sj_lower (s[0], s[1]))
+          s[1] = sj_toupper2 (s[1]);
+        s += 2;
+      }
+      else if (is_kana (*s))
+      {
+        s++;
+      }
+      else
+      {
+        if (islower(*s))
+          *s = toupper(*s);
+        s++;
+      }
+    }
+    else
+#endif /* KANJI_WIN95_COMPATIBILITY */
     {
-#ifdef KANJI
-       if (is_shift_jis (*s)) {
-           s += 2;
-       } else if (is_kana (*s)) {
-           s++;
-       } else {
-           if (islower(*s))
-               *s = toupper(*s);
-           s++;
-       }
-#else
       if (islower(*s))
-       *s = toupper(*s);
+        *s = toupper(*s);
       s++;
-#endif
     }
+  }
 }
 
 /*******************************************************************
@@ -931,23 +1191,39 @@ BOOL strisnormal(char *s)
 void string_replace(char *s,char oldc,char newc)
 {
   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. */
+      if (is_shift_jis (*s))
+        s += 2;
+      else if (is_kana (*s))
+        s++;
+      else
+      {
+        if (oldc == *s)
+          *s = newc;
+        s++;
+      }
+    }
+    else
+#endif /* KANJI_WIN95_COMPATIBILITY */
     {
-#ifdef KANJI
-       if (is_shift_jis (*s)) {
-           s += 2;
-       } else if (is_kana (*s)) {
-           s++;
-       } else {
-           if (oldc == *s)
-               *s = newc;
-           s++;
-       }
-#else
       if (oldc == *s)
-       *s = newc;
+        *s = newc;
       s++;
-#endif /* KANJI */
     }
+  }
 }
 
 /****************************************************************************
@@ -957,13 +1233,10 @@ void unix_format(char *fname)
 {
   pstring namecopy;
   string_replace(fname,'\\','/');
-#ifndef KANJI
-  dos2unix_format(fname, True);
-#endif /* KANJI */
 
   if (*fname == '/')
     {
-      strcpy(namecopy,fname);
+      pstrcpy(namecopy,fname);
       strcpy(fname,".");
       strcat(fname,namecopy);
     }  
@@ -974,9 +1247,6 @@ void unix_format(char *fname)
 ****************************************************************************/
 void dos_format(char *fname)
 {
-#ifndef KANJI
-  unix2dos_format(fname, True);
-#endif /* KANJI */
   string_replace(fname,'/','\\');
 }
 
@@ -988,8 +1258,8 @@ void show_msg(char *buf)
 {
   int i;
   int bcc=0;
-  if (DEBUGLEVEL < 5)
-    return;
+
+  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),
@@ -1005,16 +1275,17 @@ void show_msg(char *buf)
          (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,128);i++)
-    DEBUG(10,("%X ",CVAL(smb_buf(buf),i)));
-  DEBUG(10,("\n"));  
+
+  if (DEBUGLEVEL < 10) return;
+
+  dump_data(10, smb_buf(buf), MIN(bcc, 512));
 }
 
 /*******************************************************************
@@ -1157,7 +1428,7 @@ void dos_clean_name(char *s)
       pstring s1;
 
       *p = 0;
-      strcpy(s1,p+3);
+      pstrcpy(s1,p+3);
 
       if ((p=strrchr(s,'\\')) != NULL)
        *p = 0;
@@ -1183,12 +1454,19 @@ void unix_clean_name(char *s)
   /* remove any double slashes */
   string_sub(s, "//","/");
 
+  /* Remove leading ./ characters */
+  if(strncmp(s, "./", 2) == 0) {
+    trim_string(s, "./", NULL);
+    if(*s == 0)
+      strcpy(s,"./");
+  }
+
   while ((p = strstr(s,"/../")) != NULL)
     {
       pstring s1;
 
       *p = 0;
-      strcpy(s1,p+3);
+      pstrcpy(s1,p+3);
 
       if ((p=strrchr(s,'/')) != NULL)
        *p = 0;
@@ -1215,24 +1493,10 @@ 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);
 }
 
-
-/*******************************************************************
-  return the absolute current directory path. A dumb version.
-********************************************************************/
-static char *Dumb_GetWd(char *s)
-{
-#ifdef USE_GETCWD
-    return ((char *)getcwd(s,sizeof(pstring)));
-#else
-    return ((char *)getwd(s));
-#endif
-}
-
-
 /* number of list structures for a caching GetWd function. */
 #define MAX_GETWDCACHE (50)
 
@@ -1259,7 +1523,7 @@ char *GetWd(char *str)
   *s = 0;
 
   if (!use_getwd_cache)
-    return(Dumb_GetWd(str));
+    return(sys_getwd(str));
 
   /* init the cache */
   if (!getwd_cache_init)
@@ -1278,7 +1542,7 @@ char *GetWd(char *str)
   if (stat(".",&st) == -1) 
     {
       DEBUG(0,("Very strange, couldn't stat \".\"\n"));
-      return(Dumb_GetWd(str));
+      return(sys_getwd(str));
     }
 
 
@@ -1322,9 +1586,9 @@ char *GetWd(char *str)
       The very slow getcwd, which spawns a process on some systems, or the
       not quite so bad getwd. */
 
-  if (!Dumb_GetWd(s))
+  if (!sys_getwd(s))
     {
-      DEBUG(0,("Getwd failed, errno %d\n",errno));
+      DEBUG(0,("Getwd failed, errno %s\n",strerror(errno)));
       return (NULL);
     }
 
@@ -1361,12 +1625,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)
     {
@@ -1377,6 +1641,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
          DEBUG(3,("Illegal file name? (%s)\n",s));
          return(False);
        }
+
+      if (strlen(s) == 0)
+        strcpy(s,"./");
+
       return(True);
     }
   
@@ -1385,8 +1653,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);
@@ -1411,7 +1679,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)
@@ -1420,10 +1688,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);
     }
 
@@ -1434,7 +1702,7 @@ 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);
@@ -1455,12 +1723,12 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
     if (relative)
       {
        if (newname[l] == '/')
-         strcpy(s,newname + l + 1);
+         pstrcpy(s,newname + l + 1);
        else
-         strcpy(s,newname+l);
+         pstrcpy(s,newname+l);
       }
     else
-      strcpy(s,newname);
+      pstrcpy(s,newname);
   }
 
   ChDir(wd);
@@ -1484,10 +1752,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);      
     }
 }
 
@@ -1511,20 +1779,20 @@ void expand_mask(char *Mask,BOOL doext)
 
   filename_dos(Mask,filepart);
 
-  strcpy(mbeg,filepart);
+  pstrcpy(mbeg,filepart);
   if ((p1 = strchr(mbeg,'.')) != NULL)
     {
       hasdot = True;
       *p1 = 0;
       p1++;
-      strcpy(mext,p1);
+      pstrcpy(mext,p1);
     }
   else
     {
       strcpy(mext,"");
       if (strlen(mbeg) > 8)
        {
-         strcpy(mext,mbeg + 8);
+         pstrcpy(mext,mbeg + 8);
          mbeg[8] = 0;
        }
     }
@@ -1542,7 +1810,7 @@ void expand_mask(char *Mask,BOOL doext)
   if (*mext)
     expand_one(mext,3);
 
-  strcpy(Mask,dirpart);
+  pstrcpy(Mask,dirpart);
   if (*dirpart || absolute) strcat(Mask,"\\");
   strcat(Mask,mbeg);
   strcat(Mask,".");
@@ -1558,21 +1826,39 @@ does a string have any uppercase chars in it?
 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)
     {
-#ifdef KANJI
-       if (is_shift_jis (*s)) {
-           s += 2;
-       } else if (is_kana (*s)) {
-           s++;
-       } else {
-           if (isupper(*s)) return(True);
-           s++;
-       }
-#else 
-      if (isupper(*s)) return(True);
+      /* Win95 treats full width ascii characters as case sensitive. */
+      if (is_shift_jis (*s))
+        s += 2;
+      else if (is_kana (*s))
+        s++;
+      else
+      {
+        if (isupper(*s))
+          return(True);
+        s++;
+      }
+    }
+    else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+    {
+      if (isupper(*s))
+        return(True);
       s++;
-#endif /* KANJI */
     }
+  }
   return(False);
 }
 
@@ -1582,21 +1868,47 @@ does a string have any lowercase chars in it?
 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)
     {
-#ifdef KANJI
-       if (is_shift_jis (*s)) {
-           s += 2;
-       } else if (is_kana (*s)) {
-           s++;
-       } else {
-           if (islower(*s)) return(True);
-           s++;
-       }
-#else 
-      if (islower(*s)) return(True);
+      /* Win95 treats full width ascii characters as case sensitive. */
+      if (is_shift_jis (*s))
+      {
+        if (is_sj_upper (s[0], s[1]))
+          return(True);
+        if (is_sj_lower (s[0], s[1]))
+          return (True);
+        s += 2;
+      }
+      else if (is_kana (*s))
+      {
+        s++;
+      }
+      else
+      {
+        if (islower(*s))
+          return(True);
+        s++;
+      }
+    }
+    else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+    {
+      if (islower(*s))
+        return(True);
       s++;
-#endif /* KANJI */
     }
+  }
   return(False);
 }
 
@@ -1606,12 +1918,42 @@ find the number of chars in a string
 int count_chars(char *s,char c)
 {
   int count=0;
-  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. */
+    while (*s) 
+    {
+      if (is_shift_jis (*s))
+        s += 2;
+      else 
+      {
+        if (*s == c)
+          count++;
+        s++;
+      }
+    }
+  }
+  else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+  {
+    while (*s) 
     {
       if (*s == c)
-       count++;
+        count++;
       s++;
     }
+  }
   return(count);
 }
 
@@ -1624,7 +1966,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;
@@ -1682,7 +2024,7 @@ else
 if SYSV use O_NDELAY
 if BSD use FNDELAY
 ****************************************************************************/
-int set_blocking(int fd, int set)
+int set_blocking(int fd, BOOL set)
 {
   int val;
 #ifdef O_NONBLOCK
@@ -1719,6 +2061,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);
 }
 
@@ -1728,20 +2074,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=%d\n",errno));
+    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);
 }
@@ -2013,38 +2362,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));
@@ -2052,13 +2393,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 and return it's length
-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;
 
@@ -2066,8 +2433,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) {
@@ -2076,26 +2443,271 @@ 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);
 }
 
-
 /****************************************************************************
-  send an smb to a fd 
+  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.
 ****************************************************************************/
-BOOL send_smb(int fd,char *buffer)
+
+BOOL client_receive_smb(int fd,char *buffer, int timeout)
 {
-  int len;
-  int ret,nwritten=0;
-  len = smb_len(buffer) + 4;
+  BOOL ret;
 
-  while (nwritten < len)
+  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_local_message(int fd, char *buffer, int buffer_len, int timeout)
+{
+  struct sockaddr_in from;
+  int fromlen = sizeof(from);
+  int32 msg_len = 0;
+
+  if(timeout != 0)
+  {
+    struct timeval to;
+    fd_set fds;
+    int selrtn;
+
+    FD_ZERO(&fds);
+    FD_SET(fd,&fds);
+
+    to.tv_sec = timeout / 1000;
+    to.tv_usec = (timeout % 1000) * 1000;
+
+    selrtn = sys_select(&fds,&to);
+
+    /* Check if error */
+    if(selrtn == -1) 
+    {
+      /* something is wrong. Maybe the socket is dead? */
+      smb_read_error = READ_ERROR;
+      return False;
+    } 
+    
+    /* Did we timeout ? */
+    if (selrtn == 0) 
+    {
+      smb_read_error = READ_TIMEOUT;
+      return False;
+    }
+  }
+
+  /*
+   * Read a loopback udp message.
+   */
+  msg_len = recvfrom(fd, &buffer[UDP_CMD_HEADER_LEN], 
+                     buffer_len - UDP_CMD_HEADER_LEN, 0,
+                     (struct sockaddr *)&from, &fromlen);
+
+  if(msg_len < 0)
+  {
+    DEBUG(0,("receive_local_message. Error in recvfrom. (%s).\n",strerror(errno)));
+    return False;
+  }
+
+  /* Validate message length. */
+  if(msg_len > (buffer_len - UDP_CMD_HEADER_LEN))
+  {
+    DEBUG(0,("receive_local_message: invalid msg_len (%d) max can be %d\n",
+              msg_len, 
+              buffer_len  - UDP_CMD_HEADER_LEN));
+    return False;
+  }
+
+  /* Validate message from address (must be localhost). */
+  if(from.sin_addr.s_addr != htonl(INADDR_LOOPBACK))
+  {
+    DEBUG(0,("receive_local_message: invalid 'from' address \
+(was %x should be 127.0.0.1\n", from.sin_addr.s_addr));
+   return False;
+  }
+
+  /* Setup the message header */
+  SIVAL(buffer,UDP_CMD_LEN_OFFSET,msg_len);
+  SSVAL(buffer,UDP_CMD_PORT_OFFSET,ntohs(from.sin_port));
+
+  return True;
+}
+
+/****************************************************************************
+ structure to hold a linked list of local 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;
+
+  *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);
+
+  to.tv_sec = timeout / 1000;
+  to.tv_usec = (timeout % 1000) * 1000;
+
+  selrtn = sys_select(&fds,timeout>0?&to:NULL);
+
+  /* Check if error */
+  if(selrtn == -1) {
+    /* something is wrong. Maybe the socket is dead? */
+    smb_read_error = READ_ERROR;
+    return False;
+  } 
+    
+  /* Did we timeout ? */
+  if (selrtn == 0) {
+    smb_read_error = READ_TIMEOUT;
+    return False;
+  }
+
+  if (FD_ISSET(smbfd,&fds))
+  {
+    *got_smb = True;
+    return receive_smb(smbfd, buffer, 0);
+  }
+  else
+  {
+    return receive_local_message(oplock_fd, buffer, buffer_len, 0);
+  }
+}
+
+/****************************************************************************
+  send an smb to a fd 
+****************************************************************************/
+BOOL send_smb(int fd,char *buffer)
+{
+  int len;
+  int ret,nwritten=0;
+  len = smb_len(buffer) + 4;
+
+  while (nwritten < len)
     {
       ret = write_socket(fd,buffer+nwritten,len - nwritten);
       if (ret <= 0)
@@ -2143,21 +2755,27 @@ int name_extract(char *buf,int ofs,char *name)
   strcpy(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
@@ -2193,8 +2811,8 @@ BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type)
   ret = (sendto(out_fd,buf,len,0,(struct sockaddr *)&sock_out,sizeof(sock_out)) >= 0);
 
   if (!ret)
-    DEBUG(0,("Packet send to %s(%d) failed ERRNO=%d\n",
-            inet_ntoa(ip),port,errno));
+    DEBUG(0,("Packet send to %s(%d) failed ERRNO=%s\n",
+            inet_ntoa(ip),port,strerror(errno)));
 
   close(out_fd);
   return(ret);
@@ -2272,7 +2890,12 @@ BOOL string_init(char **dest,char *src)
     }
   else
     {
-      *dest = (char *)malloc(l+1);
+      (*dest) = (char *)malloc(l+1);
+      if ((*dest) == NULL) {
+             DEBUG(0,("Out of memory in string_init\n"));
+             return False;
+      }
+
       strcpy(*dest,src);
     }
   return(True);
@@ -2441,35 +3064,35 @@ BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
 
   if (strequal(p1,"*")) return(True);
 
-  DEBUG(5,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
+  DEBUG(8,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
 
   if (trans2) {
-    strcpy(ebase,p1);
-    strcpy(sbase,p2);
+    fstrcpy(ebase,p1);
+    fstrcpy(sbase,p2);
   } else {
     if ((p=strrchr(p1,'.'))) {
       *p = 0;
-      strcpy(ebase,p1);
-      strcpy(eext,p+1);
+      fstrcpy(ebase,p1);
+      fstrcpy(eext,p+1);
     } else {
-      strcpy(ebase,p1);
+      fstrcpy(ebase,p1);
       eext[0] = 0;
     }
 
   if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) {
     *p = 0;
-    strcpy(sbase,p2);
-    strcpy(sext,p+1);
+    fstrcpy(sbase,p2);
+    fstrcpy(sext,p+1);
   } else {
-    strcpy(sbase,p2);
-    strcpy(sext,"");
+    fstrcpy(sbase,p2);
+    fstrcpy(sext,"");
   }
   }
 
   matched = do_match(sbase,ebase,case_sig) && 
     (trans2 || do_match(sext,eext,case_sig));
 
-  DEBUG(5,("mask_match returning %d\n", matched));
+  DEBUG(8,("mask_match returning %d\n", matched));
 
   return matched;
 }
@@ -2483,12 +3106,12 @@ void become_daemon(void)
 {
 #ifndef NO_FORK_DEBUG
   if (fork())
-    exit(0);
+    _exit(0);
 
   /* detach from the terminal */
 #ifdef USE_SETSID
   setsid();
-#else
+#else /* USE_SETSID */
 #ifdef TIOCNOTTY
   {
     int i = open("/dev/tty", O_RDWR);
@@ -2498,9 +3121,11 @@ void become_daemon(void)
        close(i);
       }
   }
-#endif
-#endif
-#endif
+#endif /* TIOCNOTTY */
+#endif /* USE_SETSID */
+  /* Close fd's 0,1,2. Needed if started by rsh */
+  close_low_fds();
+#endif /* NO_FORK_DEBUG */
 }
 
 
@@ -2776,7 +3401,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)
@@ -2821,7 +3446,7 @@ int open_socket_in(int type, int port, int dlevel,uint32 socket_addr)
   
   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 */
+#if defined(__FreeBSD__) || defined(NETBSD) || defined(__OpenBSD__) /* XXX not the right ifdef */
   sock.sin_len = sizeof(sock);
 #endif
   sock.sin_port = htons( port );
@@ -2841,8 +3466,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)
@@ -2884,7 +3509,7 @@ int open_socket_out(int type, struct in_addr *addr, int port ,int timeout)
   sock_out.sin_family = PF_INET;
 
   /* set it non-blocking */
-  set_blocking(res,0);
+  set_blocking(res,False);
 
   DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port));
   
@@ -2892,12 +3517,15 @@ int open_socket_out(int type, struct in_addr *addr, int port ,int timeout)
 connect_again:
   ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out));
 
-  if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY) && loops--) {
+  /* Some systems return EAGAIN when they mean EINPROGRESS */
+  if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+        errno == EAGAIN) && loops--) {
     msleep(connect_loop);
     goto connect_again;
   }
 
-  if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY)) {
+  if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+         errno == EAGAIN)) {
       DEBUG(1,("timeout connecting to %s:%d\n",inet_ntoa(*addr),port));
       close(res);
       return -1;
@@ -2917,7 +3545,7 @@ connect_again:
   }
 
   /* set it blocking again */
-  set_blocking(res,1);
+  set_blocking(res,True);
 
   return res;
 }
@@ -2991,6 +3619,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);
   }
 
@@ -3021,7 +3653,9 @@ BOOL zero_ip(struct in_addr ip)
 }
 
 
-/* matchname - determine if host name matches IP address */
+/*******************************************************************
+ matchname - determine if host name matches IP address 
+ ******************************************************************/
 static BOOL matchname(char *remotehost,struct in_addr  addr)
 {
   struct hostent *hp;
@@ -3064,114 +3698,317 @@ static BOOL matchname(char *remotehost,struct in_addr  addr)
   return False;
 }
 
-/* return the DNS name of the client */
-char *client_name(void)
+/*******************************************************************
+ Reset the 'done' variables so after a client process is created
+ from a fork call these calls will be re-done. This should be
+ expanded if more variables need reseting.
+ ******************************************************************/
+
+static BOOL global_client_name_done = False;
+static BOOL global_client_addr_done = False;
+
+void reset_globals_after_fork()
 {
-  extern int Client;
-  struct sockaddr sa;
-  struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
-  int     length = sizeof(sa);
-  static pstring name_buf;
-  static BOOL done = False;
-  struct hostent *hp;
+  global_client_name_done = False;
+  global_client_addr_done = False;
+}
+/*******************************************************************
+ return the DNS name of the client 
+ ******************************************************************/
+char *client_name(int fd)
+{
+       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;
+       
+       strcpy(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)));
+                       strcpy(name_buf,"UNKNOWN");
+               }
+       }
+       global_client_name_done = True;
+       return name_buf;
+}
+
+/*******************************************************************
+ return the IP addr of the client as a string 
+ ******************************************************************/
+char *client_addr(int fd)
+{
+       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 && fd == last_fd) 
+               return addr_buf;
+
+       last_fd = fd;
+       global_client_addr_done = False;
+
+       strcpy(addr_buf,"0.0.0.0");
 
-  if (done) 
-    return name_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;
+}
 
-  done = True;
-  strcpy(name_buf,"UNKNOWN");
+/*******************************************************************
+ 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. 
+*******************************************************************/
+
+#if (defined(NETGROUP) && defined(AUTOMOUNT))
+static char *automount_lookup(char *user_name)
+{
+  static fstring last_key = "";
+  static pstring last_value = "";
 
-  if (getpeername(Client, &sa, &length) < 0) {
-    DEBUG(0,("getpeername failed\n"));
-    return name_buf;
+  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;
   }
 
-  /* 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");
+  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';
   }
-  return name_buf;
+
+  DEBUG(4, ("YP Lookup: %s resulted in %s\n", user_name, last_value));
+  return last_value;
 }
+#endif
+
+/*******************************************************************
+ Patch from jkf@soton.ac.uk
+ This is Luke's original function with the NIS lookup code
+ moved out to a separate function.
+*******************************************************************/
 
-/* return the IP addr of the client as a string */
-char *client_addr(void)
+char *automount_server(char *user_name)
 {
-  extern int Client;
-  struct sockaddr sa;
-  struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
-  int     length = sizeof(sa);
-  static fstring addr_buf;
-  static BOOL done = False;
+       static pstring server_name;
 
-  if (done) 
-    return addr_buf;
+#if (defined(NETGROUP) && defined (AUTOMOUNT))
+       int home_server_len;
 
-  done = True;
-  strcpy(addr_buf,"0.0.0.0");
+       /* set to default of local machine */
+       pstrcpy(server_name, local_machine);
 
-  if (getpeername(Client, &sa, &length) < 0) {
-    DEBUG(0,("getpeername failed\n"));
-    return addr_buf;
-  }
+       if (lp_nis_home_map())
+       {
+               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';
+       }
+#else
+       /* use the local machine name instead of the auto-map server */
+       pstrcpy(server_name, local_machine);
+#endif
 
-  strcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
+       DEBUG(4,("Home server: %s\n", server_name));
 
-  return addr_buf;
+       return server_name;
 }
 
 /*******************************************************************
-sub strings with useful parameters
-********************************************************************/
-void standard_sub_basic(char *s)
-{
-  if (!strchr(s,'%')) return;
+ Patch from jkf@soton.ac.uk
+ Added this to implement %p (NIS auto-map version of %H)
+*******************************************************************/
 
-  string_sub(s,"%R",remote_proto);
-  string_sub(s,"%a",remote_arch);
-  string_sub(s,"%m",remote_machine);
-  string_sub(s,"%L",local_machine);
+char *automount_path(char *user_name)
+{
+       static pstring server_path;
 
-  if (!strchr(s,'%')) return;
+#if (defined(NETGROUP) && defined (AUTOMOUNT))
+       char *home_path_start;
 
-  string_sub(s,"%v",VERSION);
-  string_sub(s,"%h",myhostname);
-  string_sub(s,"%U",sesssetup_user);
+       /* set to default of no string */
+       server_path[0] = 0;
 
-  if (!strchr(s,'%')) return;
+       if (lp_nis_home_map())
+       {
+               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):""));
+                 strcpy(server_path, home_path_start+1);
+               }
+       }
+#else
+       /* use the passwd entry instead of the auto-map server entry */
+       /* pstrcpy() copes with get_home_dir() returning NULL */
+       pstrcpy(server_path, get_home_dir(user_name));
+#endif
 
-  string_sub(s,"%I",client_addr());
-  if (strstr(s,"%M"))
-    string_sub(s,"%M",client_name());
-  string_sub(s,"%T",timestring());
+       DEBUG(4,("Home server path: %s\n", server_path));
 
-  if (!strchr(s,'%')) return;
+       return server_path;
+}
 
-  {
-    char pidstr[10];
-    sprintf(pidstr,"%d",(int)getpid());
-    string_sub(s,"%d",pidstr);
-  }
 
-  if (!strchr(s,'%')) return;
+/*******************************************************************
+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;
 
-  {
-    struct passwd *pass = Get_Pwnam(sesssetup_user,False);
-    if (pass) {
-      string_sub(s,"%G",gidtoname(pass->pw_gid));
-    }
-  }
+       for (s = str ; s && *s && (p = strchr(s,'%')); 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 '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' :
+                       {
+                               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 '$' : /* 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?
 ********************************************************************/
@@ -3218,13 +4055,22 @@ 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 = gethostbyname(name2);
+  ret = sys_gethostbyname(name2);
   if (ret != NULL)
     {
       free(name2);
@@ -3233,7 +4079,7 @@ struct hostent *Get_Hostbyname(char *name)
 
   /* try with all lowercase */
   strlower(name2);
-  ret = gethostbyname(name2);
+  ret = sys_gethostbyname(name2);
   if (ret != NULL)
     {
       free(name2);
@@ -3242,7 +4088,7 @@ struct hostent *Get_Hostbyname(char *name)
 
   /* try with all uppercase */
   strupper(name2);
-  ret = gethostbyname(name2);
+  ret = sys_gethostbyname(name2);
   if (ret != NULL)
     {
       free(name2);
@@ -3260,29 +4106,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",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);
 }
 
 
@@ -3336,7 +4160,7 @@ 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 solen:0 /tmp/ERROR_FAULT");
 }
 #endif
 
@@ -3362,15 +4186,6 @@ char *readdirname(void *p)
 
   dname = ptr->d_name;
 
-#ifdef KANJI
-  {
-    static pstring buf;
-    strcpy(buf, dname);
-    unix_to_dos(buf, True);
-    dname = buf;
-  }
-#endif
-
 #ifdef NEXT2
   if (telldir(p) < 0) return(NULL);
 #endif
@@ -3386,107 +4201,181 @@ char *readdirname(void *p)
        broken_readdir = True;
       }
     if (broken_readdir)
-      return(dname-2);
+      dname = dname - 2;
   }
 #endif
 
+  {
+    static pstring buf;
+    pstrcpy(buf, dname);
+    unix_to_dos(buf, True);
+    dname = buf;
+  }
+
   return(dname);
 }
 
+/*******************************************************************
+ Utility function used to decide if the last component 
+ of a path matches a (possibly wildcarded) entry in a namelist.
+********************************************************************/
 
-BOOL is_vetoed_name(char *name)
+BOOL is_in_path(char *name, name_compare_entry *namelist)
 {
-  char *namelist = lp_veto_files();
-  char *nameptr = namelist;
-  char *name_end;
+  pstring last_component;
+  char *p;
 
-  /* if we have no list it's obviously not vetoed */
-  if((nameptr == NULL ) || (*nameptr == '\0')) 
-    return 0;
+  DEBUG(8, ("is_in_path: %s\n", name));
 
-  /* if the name doesn't exist in the list, it's obviously ok too */
-  if(strstr(namelist,name) == NULL ) 
-    return 0;
+  /* if we have no list it's obviously not in the path */
+  if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL))) 
+  {
+    DEBUG(8,("is_in_path: no name list.\n"));
+    return False;
+  }
 
-  /* now, we need to find the names one by one and check them
-     they can contain spaces and all sorts of stuff so we
-     separate them with of all things '/' which can never be in a filename
-     I could use "" but then I have to break them all out
-     maybe such a routine exists somewhere?
-  */
-  while(*nameptr) 
+  /* Get the last component of the unix name. */
+  p = strrchr(name, '/');
+  strncpy(last_component, p ? p : name, sizeof(last_component)-1);
+  last_component[sizeof(last_component)-1] = '\0'; 
+
+  for(; namelist->name != NULL; namelist++)
+  {
+    if(namelist->is_wild)
     {
-      if ( *nameptr == '/' ) 
-        {
-          nameptr++;
-          continue;
-        }
-      if(name_end = strchr(nameptr,'/')) 
+      /* look for a wildcard match. */
+      if (mask_match(last_component, namelist->name, case_sensitive, False))
+      {
+         DEBUG(8,("is_in_path: mask match succeeded\n"));
+         return True;
+      }
+    }
+    else
+    {
+      if((case_sensitive && (strcmp(last_component, namelist->name) == 0))||
+       (!case_sensitive && (StrCaseCmp(last_component, namelist->name) == 0)))
         {
-          *name_end = 0;
+         DEBUG(8,("is_in_path: match succeeded\n"));
+         return True;
         }
-      /* a match! it's veto'd */
-      if(strcmp(name,nameptr) == 0) 
-        return 1;
-      if(name_end == NULL) 
-        return 0;
-      /* next segment please */
-      nameptr = name_end + 1;
     }
-  return 0;
+  }
+  DEBUG(8,("is_in_path: match not found\n"));
+  return False;
 }
 
-BOOL is_vetoed_path(char *name)
+/*******************************************************************
+ 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 *namelist = lp_veto_files();
-  char *nameptr = namelist;
-  char *sub;
   char *name_end;
-  int len;
+  char *nameptr = namelist;
+  int num_entries = 0;
+  int i;
 
-  /* if we have no list it's obviously not vetoed */
-  if((nameptr == NULL ) || (*nameptr == '\0')) 
-    return 0;
+  (*ppname_array) = NULL;
 
+  if((nameptr == NULL ) || ((nameptr != NULL) && (*nameptr == '\0'))) 
+    return;
 
-  /* now, we need to find the names one by one and check them
-     they can contain spaces and all sorts of stuff so we
-     separate them with of all things '/' which can never be in a filename
-     I could use "" but then I have to break them all out
-     maybe such a routine exists somewhere?
-  */
+  /* We need to make two passes over the string. The
+     first to count the number of elements, the second
+     to split it.
+   */
   while(*nameptr) 
     {
       if ( *nameptr == '/' ) 
         {
+          /* cope with multiple (useless) /s) */
           nameptr++;
           continue;
         }
-      if(name_end = strchr(nameptr,'/')) 
+      /* find the next / */
+      name_end = strchr(nameptr, '/');
+
+      /* oops - the last check for a / didn't find one. */
+      if (name_end == NULL)
+        break;
+
+      /* next segment please */
+      nameptr = name_end + 1;
+      num_entries++;
+    }
+
+  if(num_entries == 0)
+    return;
+
+  if(( (*ppname_array) = (name_compare_entry *)malloc( 
+           (num_entries + 1) * sizeof(name_compare_entry))) == NULL)
         {
-          *name_end = 0;
+    DEBUG(0,("set_namearray: malloc fail\n"));
+    return;
         }
 
-      len = strlen(nameptr);
-      sub = name;
-      /* If the name doesn't exist in the path, try the next name.. */
-      while( sub && ((sub = strstr(sub,nameptr)) != NULL)) 
-        {
-           /* Is it a whole component? */
-           if(((sub == name) || (sub[-1] == '/'))
-                && ((sub[len] == '\0') || (sub[len] == '/'))) 
+  /* Now copy out the names */
+  nameptr = namelist;
+  i = 0;
+  while(*nameptr)
              {
-               return 1;
-             }
-           /* skip to the next component of the path */
-              sub =strchr(sub,'/');
+      if ( *nameptr == '/' ) 
+      {
+          /* cope with multiple (useless) /s) */
+          nameptr++;
+          continue;
+      }
+      /* find the next / */
+      if ((name_end = strchr(nameptr, '/')) != NULL) 
+      {
+          *name_end = 0;
          }
+
+      /* oops - the last check for a / didn't find one. */
       if(name_end == NULL) 
-        return 0;
+        break;
+
+      (*ppname_array)[i].is_wild = ((strchr( nameptr, '?')!=NULL) ||
+                                (strchr( nameptr, '*')!=NULL));
+      if(((*ppname_array)[i].name = strdup(nameptr)) == NULL)
+      {
+        DEBUG(0,("set_namearray: malloc fail (1)\n"));
+        return;
+      }
+
       /* next segment please */
       nameptr = name_end + 1;
+      i++;
     }
-  return 0;
+  
+  (*ppname_array)[i].name = NULL;
+
+  return;
+}
+
+/****************************************************************************
+routine to free a namearray.
+****************************************************************************/
+
+void free_namearray(name_compare_entry *name_array)
+{
+  if(name_array == 0)
+    return;
+
+  if(name_array->name != NULL)
+    free(name_array->name);
+
+  free((char *)name_array);
 }
 
 /****************************************************************************
@@ -3529,7 +4418,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;
@@ -3577,7 +4466,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
@@ -3619,4 +4508,386 @@ void file_unlock(int fd)
   close(fd);
 }
 
+/*******************************************************************
+is the name specified one of my netbios names
+returns true is it is equal, false otherwise
+********************************************************************/
+BOOL is_myname(char *s)
+{
+  int n;
+  BOOL ret = False;
+
+  for (n=0; my_netbios_names[n]; n++) {
+    if (strequal(my_netbios_names[n], s))
+      ret=True;
+  }
+  DEBUG(8, ("is_myname(\"%s\") returns %d\n", s, ret));
+  return(ret);
+}
 
+/*******************************************************************
+set the horrid remote_arch string based on an enum.
+********************************************************************/
+void set_remote_arch(enum remote_arch_types type)
+{
+  ra_type = type;
+  switch( type )
+  {
+  case RA_WFWG:
+    strcpy(remote_arch, "WfWg");
+    return;
+  case RA_OS2:
+    strcpy(remote_arch, "OS2");
+    return;
+  case RA_WIN95:
+    strcpy(remote_arch, "Win95");
+    return;
+  case RA_WINNT:
+    strcpy(remote_arch, "WinNT");
+    return;
+  case RA_SAMBA:
+    strcpy(remote_arch,"Samba");
+    return;
+  default:
+    ra_type = RA_UNKNOWN;
+    strcpy(remote_arch, "UNKNOWN");
+    break;
+  }
+}
+
+/*******************************************************************
+ Get the remote_arch type.
+********************************************************************/
+enum remote_arch_types get_remote_arch()
+{
+  return ra_type;
+}
+
+
+/*******************************************************************
+skip past some unicode strings in a buffer
+********************************************************************/
+char *skip_unicode_string(char *buf,int n)
+{
+  while (n--)
+  {
+    while (*buf)
+      buf += 2;
+    buf += 2;
+  }
+  return(buf);
+}
+
+/*******************************************************************
+Return a ascii version of a unicode string
+Hack alert: uses fixed buffer(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 fstring
+********************************************************************/
+void fstrcpy(char *dest, char *src)
+{
+    int maxlength = sizeof(fstring) - 1;
+    if (!dest) {
+        DEBUG(0,("ERROR: NULL dest in fstrcpy\n"));
+        return;
+    }
+
+    if (!src) {
+        *dest = 0;
+        return;
+    }  
+      
+    while (maxlength-- && *src)
+        *dest++ = *src++;
+    *dest = 0;
+    if (*src) {
+        DEBUG(0,("ERROR: string overflow by %d in fstrcpy\n",
+             strlen(src)));
+    }    
+}   
+
+/*******************************************************************
+safe string copy into a pstring
+********************************************************************/
+void pstrcpy(char *dest, char *src)
+{
+    int maxlength = sizeof(pstring) - 1;
+    if (!dest) {
+        DEBUG(0,("ERROR: NULL dest in pstrcpy\n"));
+        return;
+    }
+   
+    if (!src) {
+        *dest = 0;
+        return;
+    }
+   
+    while (maxlength-- && *src)
+        *dest++ = *src++;
+    *dest = 0;
+    if (*src) {
+        DEBUG(0,("ERROR: string overflow by %d in pstrcpy\n",
+             strlen(src)));
+    }
+}  
+
+
+/*******************************************************************
+align a pointer to a multiple of 4 bytes
+********************************************************************/
+char *align4(char *q, char *base)
+{
+       if ((q - base) & 3)
+       {
+               q += 4 - ((q - base) & 3);
+       }
+       return q;
+}
+
+/*******************************************************************
+align a pointer to a multiple of 2 bytes
+********************************************************************/
+char *align2(char *q, char *base)
+{
+       if ((q - base) & 1)
+       {
+               q++;
+       }
+       return q;
+}
+
+/*******************************************************************
+align a pointer to a multiple of align_offset bytes.  looks like it
+will work for offsets of 0, 2 and 4...
+********************************************************************/
+char *align_offset(char *q, char *base, int align_offset_len)
+{
+       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 domain SID to an ascii string. (non-reentrant).
+*****************************************************************/
+
+/* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
+char *dom_sid_to_string(DOM_SID *sid)
+{
+  static pstring sidstr;
+  char subauth[16];
+  int i;
+  uint32 ia = (sid->id_auth[5]) +
+              (sid->id_auth[4] << 8 ) +
+              (sid->id_auth[3] << 16) +
+              (sid->id_auth[2] << 24);
+
+  sprintf(sidstr, "S-%d-%d", sid->sid_rev_num, ia);
+
+  for (i = 0; i < sid->num_auths; i++)
+  {
+    sprintf(subauth, "-%d", sid->sub_auths[i]);
+    strcat(sidstr, subauth);
+  }
+
+  DEBUG(7,("dom_sid_to_string returning %s\n", sidstr));
+  return sidstr;
+}