To: vim-dev@vim.org Subject: Patch 6.0.116 Fcc: outbox From: Bram Moolenaar MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit ------------ Patch 6.0.116 (extra) Problem: MS-Windows NT/2000/XP: filewritable() doesn't work correctly for filesystems that use ACLs. Solution: Use ACL functions to check if a file is writable. (Mike Williams) Files: src/eval.c, src/macros.h, src/os_win32.c, src/proto/os_win32.pro *** ../vim60.115/src/eval.c Tue Jan 1 15:16:42 2002 --- src/eval.c Tue Jan 1 20:50:07 2002 *************** *** 3412,3432 **** #endif p = get_var_string(&argvars[0]); ! #ifndef MACOS_CLASSIC /* TODO: get either mch_writable or mch_access */ ! #ifdef WIN3264 ! if (mch_writable(p)) ! #else ! # ifdef UNIX perm = mch_getperm(p); ! # endif if ( ! # ifdef UNIX ! (perm & 0222) && # endif ! mch_access((char *)p, W_OK) == 0 ) #endif - #endif { ++retval; if (mch_isdir(p)) --- 3412,3432 ---- #endif p = get_var_string(&argvars[0]); ! #ifdef UNIX perm = mch_getperm(p); ! #endif ! #ifndef MACOS_CLASSIC /* TODO: get either mch_writable or mch_access */ if ( ! # ifdef WIN3264 ! mch_writable(p) ! # else ! # ifdef UNIX ! (perm & 0222) ! # endif # endif ! && mch_access((char *)p, W_OK) == 0 ) #endif { ++retval; if (mch_isdir(p)) *** ../vim60.115/src/macros.h Sat Jul 28 22:50:57 2001 --- src/macros.h Tue Jan 1 20:52:19 2002 *************** *** 136,142 **** /* VMS does not have lstat() */ # define mch_stat(n, p) stat(vms_fixfilename(n), (p)) #else ! # define mch_access(n, p) access((n), (p)) # define mch_fopen(n, p) fopen((n), (p)) # define mch_fstat(n, p) fstat((n), (p)) # define mch_lstat(n, p) lstat((n), (p)) --- 136,144 ---- /* VMS does not have lstat() */ # define mch_stat(n, p) stat(vms_fixfilename(n), (p)) #else ! # ifndef WIN32 ! # define mch_access(n, p) access((n), (p)) ! # endif # define mch_fopen(n, p) fopen((n), (p)) # define mch_fstat(n, p) fstat((n), (p)) # define mch_lstat(n, p) lstat((n), (p)) *** ../vim60.115/src/os_win32.c Sun Nov 4 14:31:23 2001 --- src/os_win32.c Tue Jan 1 21:06:01 2002 *************** *** 90,103 **** --- 90,109 ---- */ #ifdef PROTO # define HANDLE int + # define PHANDLE int # define SMALL_RECT int # define COORD int # define SHORT int # define WORD int # define DWORD int + # define PDWORD int # define BOOL int + # define LPBOOL int # define LPSTR int # define LPTSTR int + # define LPCTSTR int + # define LPDWORD int + # define LPVOID int # define KEY_EVENT_RECORD int # define MOUSE_EVENT_RECORD int # define WINAPI *************** *** 119,124 **** --- 125,133 ---- # define COLORREF int # define HDC int # define LOGFONT int + # define TOKEN_INFORMATION_CLASS int + # define TRUSTEE int + # define ACCESS_MASK int #endif #ifndef FEAT_GUI_W32 *************** *** 317,322 **** --- 326,332 ---- DWORD g_PlatformId; #ifdef HAVE_ACL + # include /* * These are needed to dynamically load the ADVAPI DLL, which is not * implemented under Windows 95 (and causes VIM to crash) *************** *** 326,334 **** --- 336,358 ---- typedef DWORD (WINAPI *PGNSECINFO) (LPSTR, enum SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID *, PSID *, PACL *, PACL *, PSECURITY_DESCRIPTOR *); + typedef BOOL (WINAPI *PGFILESEC) (LPCTSTR, SECURITY_INFORMATION, + PSECURITY_DESCRIPTOR, DWORD, LPDWORD); + typedef BOOL (WINAPI *PGSECDESCDACL) (PSECURITY_DESCRIPTOR, + LPBOOL, PACL *, LPBOOL); + typedef BOOL (WINAPI *POPENPROCTOK) (HANDLE, DWORD, PHANDLE); + typedef BOOL (WINAPI *PGTOKINFO) (HANDLE, TOKEN_INFORMATION_CLASS, + LPVOID, DWORD, PDWORD); + typedef DWORD (WINAPI *PGEFFRIGHTACL) (PACL, TRUSTEE *, ACCESS_MASK *); + static HANDLE advapi_lib = NULL; /* Handle for ADVAPI library */ static PSNSECINFO pSetNamedSecurityInfo; static PGNSECINFO pGetNamedSecurityInfo; + static PGFILESEC pGetFileSecurity; + static PGSECDESCDACL pGetSecurityDescriptorDacl; + static POPENPROCTOK pOpenProcessToken; + static PGTOKINFO pGetTokenInformation; + static PGEFFRIGHTACL pGetEffectiveRightsFromAcl; #endif /* *************** *** 370,377 **** "SetNamedSecurityInfoA"); pGetNamedSecurityInfo = (PGNSECINFO)GetProcAddress(advapi_lib, "GetNamedSecurityInfoA"); if (pSetNamedSecurityInfo == NULL ! || pGetNamedSecurityInfo == NULL) { /* If we can't get the function addresses, set advapi_lib * to NULL so that we don't use them. */ --- 394,415 ---- "SetNamedSecurityInfoA"); pGetNamedSecurityInfo = (PGNSECINFO)GetProcAddress(advapi_lib, "GetNamedSecurityInfoA"); + pGetFileSecurity = (PGFILESEC)GetProcAddress(advapi_lib, + "GetFileSecurityA"); + pGetSecurityDescriptorDacl = (PGSECDESCDACL)GetProcAddress(advapi_lib, + "GetSecurityDescriptorDacl"); + pOpenProcessToken = (POPENPROCTOK)GetProcAddress(advapi_lib, + "OpenProcessToken"); + pGetTokenInformation = (PGTOKINFO)GetProcAddress(advapi_lib, + "GetTokenInformation"); + pGetEffectiveRightsFromAcl = (PGEFFRIGHTACL)GetProcAddress(advapi_lib, + "GetEffectiveRightsFromAclA"); if (pSetNamedSecurityInfo == NULL ! || pGetNamedSecurityInfo == NULL ! || pGetFileSecurity == NULL ! || pGetSecurityDescriptorDacl == NULL ! || pOpenProcessToken == NULL ! || pGetTokenInformation == NULL) { /* If we can't get the function addresses, set advapi_lib * to NULL so that we don't use them. */ *************** *** 2368,2375 **** } #ifdef HAVE_ACL - # include - struct my_acl { PSECURITY_DESCRIPTOR pSecurityDescriptor; --- 2406,2411 ---- *************** *** 4000,4003 **** --- 4036,4134 ---- psz = "command.com"; 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; + TRUSTEE t; + ACCESS_MASK am; + ACCESS_MASK cm; + PACL pacl; + static DWORD sd_bytes = 0; + static SECURITY_DESCRIPTOR* psd = NULL; + 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 */ + t.pMultipleTrustee = NULL; + t.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; + t.TrusteeForm = TRUSTEE_IS_SID; + 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; + cm |= (p & R_OK) ? FILE_READ_DATA : 0; + + /* Check access mask against modes requested */ + if ((am & cm) != cm) + return -1; + } + #endif /* HAVE_ACL */ + return access(n, p); } *** ../vim60.115/src/proto/os_win32.pro Tue Sep 25 21:49:34 2001 --- src/proto/os_win32.pro Tue Jan 1 21:03:23 2002 *************** *** 42,45 **** --- 42,46 ---- long_u mch_avail_mem __ARGS((int special)); int mch_rename __ARGS((const char *pszOldFile, const char *pszNewFile)); char *default_shell __ARGS((void)); + int mch_access __ARGS((char *n, int p)); /* vim: set ft=c : */ *** ../vim60.115/src/version.c Tue Jan 1 20:29:44 2002 --- src/version.c Tue Jan 1 21:07:53 2002 *************** *** 608,609 **** --- 608,611 ---- { /* Add new patch number below this line */ + /**/ + 116, /**/ -- ZOOT: I'm afraid our life must seem very dull and quiet compared to yours. We are but eightscore young blondes, all between sixteen and nineteen-and-a-half, cut off in this castle, with no one to protect us. Oooh. It is a lonely life ... bathing ... dressing ... undressing ... making exciting underwear.... "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@moolenaar.net -- http://www.moolenaar.net \\\ ((( Creator of Vim -- http://vim.sf.net -- ftp://ftp.vim.org/pub/vim ))) \\\ Help me helping AIDS orphans in Uganda - http://iccf-holland.org ///