To: vim-dev@vim.org
Subject: Patch 6.0.255 (extra)
Fcc: outbox
From: Bram Moolenaar <Bram@moolenaar.net>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8bit
------------

Patch 6.0.255 (extra) (depends on patch 6.0.116 and 6.0.121)
Problem:    Win32: ACL support doesn't work well on Samba drives.
Solution:   Add a check for working ACL support. (Mike Williams)
Files:	    src/os_win32.c


*** ../vim60.254/src/os_win32.c	Thu Jan 10 21:23:57 2002
--- src/os_win32.c	Thu Feb 21 20:29:28 2002
***************
*** 4035,4063 ****
      return psz;
  }
  
  /* NB: Not SACL_SECURITY_INFORMATION since we don't have enough privilege */
  #define MCH_ACCESS_SEC  (OWNER_SECURITY_INFORMATION \
  			 |GROUP_SECURITY_INFORMATION \
  			 |DACL_SECURITY_INFORMATION)
  
  /*
!  * mch_access() extends access() to support ACLs under Windows NT/2K/XP(?)
   * Does not support ACLs on NT 3.1/5 since the key function
   * GetEffectiveRightsFromAcl() does not exist and implementing its
   * functionality is a pain.
!  * Written by Mike Williams.
!  * Returns 0 if file "n" has access rights according to "p", -1 otherwise.
   */
!     int
! mch_access(char *n, int p)
  {
      BOOL			aclpresent;
      BOOL			aclDefault;
      HANDLE			hToken;
      DWORD			bytes;
- #ifdef HAVE_ACL
      TRUSTEE			t;
- #endif
      ACCESS_MASK			am;
      ACCESS_MASK			cm;
      PACL			pacl;
--- 4035,4122 ----
      return psz;
  }
  
+ #ifdef HAVE_ACL
+ /*
+  * Code to support ACLs on Windows based on hints and tips from Corinna
+  * Vinschen.
+  */
+ 
+ /*
+  * do_acl_check() provides an initial check to see if the file system the file
+  * lives on supports ACLs at all.  This is primarily for handlng network drives
+  * - one of Win9x/ME, NT/2K/XP, or Samba.
+  * If the network drive is invalid Check #1 fails.
+  * Win9X/ME and some Samba do not support ACLs at all and fail Check #2.
+  * Samba does not provide full ACL support - we detect them as case preserving
+  * but no supporting unicode file names, Check #3.
+  * NT/2K/XP support ACLs.
+  * Remark: NT 4 SP 4 (and other versions) has a broken
+  * GetEffectiveRightsFromAcl() (Vince Negri)
+  */
+     static int
+ do_acl_check(char* n)
+ {
+     DWORD   max_comp_len;
+     DWORD   file_sys_flags;
+     static char* file_root = NULL;
+     static int file_root_len = 0;
+     int     new_file_root_len;
+     char*   file_root_end;
+ 
+     /* Extract file root path */
+     file_root_end = vim_strrchr(n, '\\');
+     new_file_root_len = file_root_end - n + 1;
+     if (new_file_root_len > file_root_len)
+     {
+         vim_free(file_root);
+         file_root = (char*)alloc(new_file_root_len + 1);
+         file_root_len = new_file_root_len;
+     }
+     STRNCPY(file_root, n, new_file_root_len);
+     file_root[new_file_root_len] = '\0';
+ 
+     /* Check #1 - can we get volume information in the first place? */
+     if (!GetVolumeInformation(file_root, NULL, 0, NULL, &max_comp_len,
+                                                       &file_sys_flags, NULL, 0))
+         return FALSE;
+ 
+     /* Check #2 - does the file system support ACLs at all? */
+     if (!(file_sys_flags&FS_PERSISTENT_ACLS))
+         return FALSE;
+ 
+     /* Check #3 - does it look like a Samba file system?  Current guess is that
+      * they are the only ones that are case sensitive/preserving but do not
+      * support Unicode file names. */
+     if ((file_sys_flags&
+              (FS_CASE_IS_PRESERVED|FS_CASE_SENSITIVE|FS_UNICODE_STORED_ON_DISK))
+                                     == (FS_CASE_IS_PRESERVED|FS_CASE_SENSITIVE))
+         return FALSE;
+ 
+     /* The file system supports ACLs - do the check */
+     return TRUE;
+ }
+ 
  /* NB: Not SACL_SECURITY_INFORMATION since we don't have enough privilege */
  #define MCH_ACCESS_SEC  (OWNER_SECURITY_INFORMATION \
  			 |GROUP_SECURITY_INFORMATION \
  			 |DACL_SECURITY_INFORMATION)
  
  /*
!  * acl_check() implements ACL support under Windows NT/2K/XP(?)
   * Does not support ACLs on NT 3.1/5 since the key function
   * GetEffectiveRightsFromAcl() does not exist and implementing its
   * functionality is a pain.
!  * Returns TRUE if file "n" has access rights according to "p" FALSE otherwise.
   */
!     static int
! acl_check(char* n, int p)
  {
+     DWORD                       error;
      BOOL			aclpresent;
      BOOL			aclDefault;
      HANDLE			hToken;
      DWORD			bytes;
      TRUSTEE			t;
      ACCESS_MASK			am;
      ACCESS_MASK			cm;
      PACL			pacl;
***************
*** 4066,4114 ****
      static DWORD		tu_bytes = 0;
      static TOKEN_USER*		ptu = NULL;
  
! #ifdef HAVE_ACL
!     /* Only check ACLs if on WinNT 4.0 or later - GetEffectiveRightsFromAcl()
!      * does not exist on NT before 4.0 */
!     if (!mch_windows95()
! 	    && advapi_lib != NULL
  	    && pGetEffectiveRightsFromAcl != NULL)
      {
  	/* Get file ACL info */
  	if (!pGetFileSecurity(n, MCH_ACCESS_SEC, psd, sd_bytes, &bytes))
  	{
! 	    if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
! 		return -1;
  	    vim_free(psd);
  	    psd = (SECURITY_DESCRIPTOR *)alloc(bytes);
  	    if (psd == NULL)
  	    {
  		sd_bytes = 0;
! 		return -1;
  	    }
  	    sd_bytes = bytes;
  	    if (!pGetFileSecurity(n, MCH_ACCESS_SEC, psd, sd_bytes, &bytes))
! 		return -1;
  	}
  	if (!pGetSecurityDescriptorDacl(psd, &aclpresent, &pacl, &aclDefault))
! 	    return -1;
  
  	/* Get user security info */
  	if (!pOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
! 	    return -1;
  	if (!pGetTokenInformation(hToken, TokenUser, ptu, tu_bytes, &bytes))
  	{
  	    if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
! 		return -1;
  	    vim_free(ptu);
  	    ptu = (TOKEN_USER *)alloc(bytes);
  	    if (ptu == NULL)
  	    {
  		tu_bytes = 0;
! 		return -1;
  	    }
  	    tu_bytes = bytes;
  	    if (!pGetTokenInformation(hToken, TokenUser, ptu, tu_bytes, &bytes))
! 		return -1;
  	}
  
  	/* Lets see what user can do based on ACL */
--- 4125,4172 ----
      static DWORD		tu_bytes = 0;
      static TOKEN_USER*		ptu = NULL;
  
!     if (advapi_lib != NULL
  	    && pGetEffectiveRightsFromAcl != NULL)
      {
  	/* Get file ACL info */
  	if (!pGetFileSecurity(n, MCH_ACCESS_SEC, psd, sd_bytes, &bytes))
  	{
!             error = GetLastError();
!             if (error == ERROR_NOT_SUPPORTED)
!                 return TRUE; /* Should be filtered by do_acl_check() but ... */
! 	    if (error != ERROR_INSUFFICIENT_BUFFER)
! 		return FALSE;
  	    vim_free(psd);
  	    psd = (SECURITY_DESCRIPTOR *)alloc(bytes);
  	    if (psd == NULL)
  	    {
  		sd_bytes = 0;
! 		return FALSE;
  	    }
  	    sd_bytes = bytes;
  	    if (!pGetFileSecurity(n, MCH_ACCESS_SEC, psd, sd_bytes, &bytes))
! 		return FALSE;
  	}
  	if (!pGetSecurityDescriptorDacl(psd, &aclpresent, &pacl, &aclDefault))
! 	    return FALSE;
  
  	/* Get user security info */
  	if (!pOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
! 	    return FALSE;
  	if (!pGetTokenInformation(hToken, TokenUser, ptu, tu_bytes, &bytes))
  	{
  	    if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
! 		return FALSE;
  	    vim_free(ptu);
  	    ptu = (TOKEN_USER *)alloc(bytes);
  	    if (ptu == NULL)
  	    {
  		tu_bytes = 0;
! 		return FALSE;
  	    }
  	    tu_bytes = bytes;
  	    if (!pGetTokenInformation(hToken, TokenUser, ptu, tu_bytes, &bytes))
! 		return FALSE;
  	}
  
  	/* Lets see what user can do based on ACL */
***************
*** 4118,4124 ****
  	t.TrusteeType = TRUSTEE_IS_USER;
  	t.ptstrName = ptu->User.Sid;
  	if (pGetEffectiveRightsFromAcl(pacl, &t, &am) != ERROR_SUCCESS)
! 	    return -1;
  
  	cm = 0;
  	cm |= (p & W_OK) ? FILE_WRITE_DATA : 0;
--- 4176,4182 ----
  	t.TrusteeType = TRUSTEE_IS_USER;
  	t.ptstrName = ptu->User.Sid;
  	if (pGetEffectiveRightsFromAcl(pacl, &t, &am) != ERROR_SUCCESS)
! 	    return FALSE;
  
  	cm = 0;
  	cm |= (p & W_OK) ? FILE_WRITE_DATA : 0;
***************
*** 4126,4133 ****
  
  	/* Check access mask against modes requested */
  	if ((am & cm) != cm)
! 	    return -1;
      }
  #endif /* HAVE_ACL */
      return access(n, p);
  }
--- 4184,4207 ----
  
  	/* Check access mask against modes requested */
  	if ((am & cm) != cm)
! 	    return FALSE;
      }
+     return TRUE;
+ }
+ #endif /* HAVE_ACL */
+ 
+ /*
+  * mch_access() extends access() to support ACLs under Windows NT/2K/XP(?)
+  * Returns 0 if file "n" has access rights according to "p", -1 otherwise.
+  */
+     int
+ mch_access(char *n, int p)
+ {
+ #ifdef HAVE_ACL
+     /* Only do ACL check if not on Win 9x/ME - GetEffectiveRightsFromAcl()
+      * does not exist on NT before 4.0 */
+     if (!mch_windows95() && do_acl_check(n) && !acl_check(n, p))
+         return -1;
  #endif /* HAVE_ACL */
      return access(n, p);
  }
*** ../vim60.254/src/version.c	Thu Feb 21 20:20:08 2002
--- src/version.c	Thu Feb 21 20:29:33 2002
***************
*** 608,609 ****
--- 608,611 ----
  {   /* Add new patch number below this line */
+ /**/
+     255,
  /**/

-- 
An alien life briefly visits earth.  Just before departing it leaves a
message in the dust on the back of a white van.  The world is shocked
and wants to know what it means.  After months of studies the worlds
best linguistic scientists are able to decipher the message: "Wash me!".

 ///  Bram Moolenaar -- Bram@moolenaar.net -- http://www.moolenaar.net  \\\
///   Creator of Vim -- http://vim.sf.net -- ftp://ftp.vim.org/pub/vim   \\\
\\\           Project leader for A-A-P -- http://www.a-a-p.org           ///
 \\\  Help me helping AIDS orphans in Uganda - http://iccf-holland.org  ///