a pointless commit to check on a problem Luke reported with CVS
[kai/samba.git] / source3 / lib / util.c
index 91e3581c30e7acbc2a4806eb49770958e1932909..306e80c3073cf64b3d9e79fbba99c42ba7b0fa24 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
@@ -92,6 +92,53 @@ 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);
+#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 */
+
+
 /*******************************************************************
   get ready for syslog stuff
   ******************************************************************/
@@ -102,10 +149,10 @@ void setup_logging(char *pname,BOOL 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) {
@@ -123,7 +170,6 @@ reopen the log files
 ****************************************************************************/
 void reopen_logs(void)
 {
-  extern FILE *dbf;
   pstring fname;
   
   if (DEBUGLEVEL > 0)
@@ -841,6 +887,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. */
@@ -905,6 +960,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. */
@@ -953,10 +1017,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 */
@@ -1011,6 +1076,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. */
@@ -1049,6 +1123,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. */
@@ -1110,6 +1193,15 @@ 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. */
@@ -1165,10 +1257,9 @@ void dos_format(char *fname)
 void show_msg(char *buf)
 {
   int i;
-  int j;
   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),
@@ -1184,35 +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, 512); i += 16)
-  {
-    for (j = 0; j < 16 && i+j < MIN(bcc,512); j++)
-    {
-
-      DEBUG(10,("%2X ",CVAL(smb_buf(buf),i+j)));
-      if (j == 7) DEBUG(10, ("  "));
 
-    }
-    DEBUG(10,("  "));  
-
-    for (j = 0; j < 16 && i+j < MIN(bcc,512); 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, ("  "));
-    }
-
-  DEBUG(10,("\n"));  
-}
+  dump_data(10, smb_buf(buf), MIN(bcc, 512));
 }
 
 /*******************************************************************
@@ -1552,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)
     {
@@ -1580,8 +1653,8 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
   /* remove any double slashes */
   string_sub(s,"//","/");
 
-  pstrcpy(basename,s);
-  p = strrchr(basename,'/');
+  pstrcpy(base_name,s);
+  p = strrchr(base_name,'/');
 
   if (!p)
     return(True);
@@ -1606,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)
@@ -1615,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);
     }
 
@@ -1629,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);
@@ -1755,6 +1828,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. */
@@ -1788,6 +1870,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. */
@@ -1829,6 +1920,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. */
@@ -1961,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);
 }
 
@@ -1970,20 +2074,20 @@ 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));
@@ -2258,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));
@@ -2297,12 +2393,37 @@ 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. Note that the buffer *MUST* be of size
   BUFFER_SIZE+SAFETY_MARGIN.
-The timeout is in milli seconds
+  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)
 {
@@ -2312,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) {
@@ -2322,15 +2443,45 @@ 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);
 }
 
+/****************************************************************************
+  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 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
@@ -2409,29 +2560,31 @@ BOOL receive_local_message(int fd, char *buffer, int buffer_len, int timeout)
 }
 
 /****************************************************************************
- structure to hold a linked list of local udp messages.
+ structure to hold a linked list of local messages.
  for processing.
 ****************************************************************************/
 
-typedef struct _udp_message_list {
-   struct _udp_message_list *msg_next;
+typedef struct _message_list {
+   struct _message_list *msg_next;
    char *msg_buf;
    int msg_len;
-} udp_message_list;
+} pending_message_list;
 
-static udp_message_list *udp_msg_head = NULL;
+static pending_message_list *smb_msg_head = NULL;
 
 /****************************************************************************
- Function to push a linked list of local udp messages ready
+ Function to push a linked list of local messages ready
  for processing.
 ****************************************************************************/
-BOOL push_local_message(char *buf, int msg_len)
+
+static BOOL push_local_message(pending_message_list **pml, char *buf, int msg_len)
 {
-  udp_message_list *msg = (udp_message_list *)malloc(sizeof(udp_message_list));
+  pending_message_list *msg = (pending_message_list *)
+                               malloc(sizeof(pending_message_list));
 
   if(msg == NULL)
   {
-    DEBUG(0,("push_local_message: malloc fail (1)\n"));
+    DEBUG(0,("push_message: malloc fail (1)\n"));
     return False;
   }
 
@@ -2446,12 +2599,22 @@ BOOL push_local_message(char *buf, int msg_len)
   memcpy(msg->msg_buf, buf, msg_len);
   msg->msg_len = msg_len;
 
-  msg->msg_next = udp_msg_head;
-  udp_msg_head = msg;
+  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. 
 
@@ -2459,6 +2622,10 @@ BOOL push_local_message(char *buf, int msg_len)
   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
@@ -2479,19 +2646,22 @@ BOOL receive_message_or_smb(int smbfd, int oplock_fd,
   *got_smb = False;
 
   /*
-   * Check to see if we already have a message on the udp queue.
+   * Check to see if we already have a message on the smb queue.
    * If so - copy and return it.
    */
-
-  if(udp_msg_head)
+  
+  if(smb_msg_head)
   {
-    udp_message_list *msg = udp_msg_head;
+    pending_message_list *msg = smb_msg_head;
     memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len));
-    udp_msg_head = msg->msg_next;
-
+    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;
   }
 
@@ -2936,7 +3106,7 @@ void become_daemon(void)
 {
 #ifndef NO_FORK_DEBUG
   if (fork())
-    exit(0);
+    _exit(0);
 
   /* detach from the terminal */
 #ifdef USE_SETSID
@@ -3276,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 );
@@ -3546,107 +3716,166 @@ void reset_globals_after_fork()
 /*******************************************************************
  return the DNS name of the client 
  ******************************************************************/
-char *client_name(void)
+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)
 {
-  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;
+       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_name_done
-    return name_buf;
+       if (global_client_addr_done && fd == last_fd
+               return addr_buf;
 
-  strcpy(name_buf,"UNKNOWN");
+       last_fd = fd;
+       global_client_addr_done = False;
 
-  if (getpeername(Client, &sa, &length) < 0) {
-    DEBUG(0,("getpeername failed\n"));
-    return name_buf;
-  }
+       strcpy(addr_buf,"0.0.0.0");
 
-  /* 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;
+       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;
 }
 
 /*******************************************************************
- return the IP addr of the client as a string 
- ******************************************************************/
-char *client_addr(void)
-{
-  extern int Client;
-  struct sockaddr sa;
-  struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
-  int     length = sizeof(sa);
-  static fstring addr_buf;
+ 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 (global_client_addr_done) 
-    return addr_buf;
+#if (defined(NETGROUP) && defined(AUTOMOUNT))
+static char *automount_lookup(char *user_name)
+{
+  static fstring last_key = "";
+  static pstring last_value = "";
 
-  strcpy(addr_buf,"0.0.0.0");
+  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 (getpeername(Client, &sa, &length) < 0) {
-    DEBUG(0,("getpeername failed\n"));
-    return addr_buf;
+  if ((nis_error = yp_get_default_domain(&nis_domain)) != 0)
+  {
+    DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error)));
+    return last_value;
   }
 
-  fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
+  DEBUG(5, ("NIS Domain: %s\n", nis_domain));
 
-  global_client_addr_done = True;
-  return addr_buf;
+  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';
+  }
+
+  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.
+*******************************************************************/
 
 char *automount_server(char *user_name)
 {
        static pstring server_name;
 
 #if (defined(NETGROUP) && defined (AUTOMOUNT))
-       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();
        int home_server_len;
 
-       /* set to default of no string */
-       server_name[0] = 0;
-
-       if ((nis_error = yp_get_default_domain(&nis_domain)) != 0)
-       {
-               DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error)));
-       }
-
-       DEBUG(5, ("NIS Domain: %s\n", nis_domain));
-
-       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\n", yperr_string(nis_error)));
-       }
+       /* set to default of local machine */
+       pstrcpy(server_name, local_machine);
 
-       if (!nis_error && lp_nis_home_map())
+       if (lp_nis_home_map())
        {
-               home_server_len = strcspn(nis_result,":");
+               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, nis_result, home_server_len);
+               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 */
@@ -3658,6 +3887,44 @@ char *automount_server(char *user_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;
+
+#if (defined(NETGROUP) && defined (AUTOMOUNT))
+       char *home_path_start;
+
+       /* set to default of no string */
+       server_path[0] = 0;
+
+       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
+
+       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
@@ -3670,7 +3937,7 @@ void standard_sub_basic(char *str)
        struct passwd *pass;
        char *username = sam_logon_in_ssb ? samlogon_user : sesssetup_user;
 
-       for (s = str ; (p = strchr(s,'%')) != NULL ; s = p )
+       for (s = str ; s && *s && (p = strchr(s,'%')); s = p )
        {
                switch (*(p+1))
                {
@@ -3687,9 +3954,9 @@ void standard_sub_basic(char *str)
                                break;
                        }
                        case 'N' : string_sub(p,"%N", automount_server(username)); break;
-                       case 'I' : string_sub(p,"%I", client_addr()); 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()); 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;
@@ -3703,6 +3970,38 @@ void standard_sub_basic(char *str)
                        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;
                }
@@ -3756,11 +4055,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)
@@ -3798,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",(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);
 }
 
 
@@ -3874,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
 
@@ -4303,11 +4589,19 @@ char *unistrn2(uint16 *buf, int len)
        static int nexti;
        char *lbuf = lbufs[nexti];
        char *p;
+
        nexti = (nexti+1)%8;
-       for (p = lbuf; *buf && p-lbuf < MAXUNI-2 && len >= 0; len--, p++, buf++)
+
+       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;
 }
@@ -4323,15 +4617,54 @@ char *unistr2(uint16 *buf)
        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
@@ -4484,7 +4817,7 @@ char *align_offset(char *q, char *base, int align_offset_len)
        return q;
 }
 
-static void print_asc(int level, unsigned char *buf,int len)
+void print_asc(int level, unsigned char *buf,int len)
 {
        int i;
        for (i=0;i<len;i++)
@@ -4532,4 +4865,29 @@ char *tab_depth(int depth)
        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;
+}