Skip to content

Instantly share code, notes, and snippets.

@k-takata
Created August 27, 2012 14:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save k-takata/3489193 to your computer and use it in GitHub Desktop.
Save k-takata/3489193 to your computer and use it in GitHub Desktop.
fix ACL setting on Win32
diff -r 536aa8b0c934 src/os_win32.c
--- a/src/os_win32.c Wed Aug 15 17:43:31 2012 +0200
+++ b/src/os_win32.c Fri Aug 31 19:26:04 2012 +0900
@@ -433,19 +433,33 @@
#ifdef HAVE_ACL
# include <aclapi.h>
+# ifndef PROTECTED_DACL_SECURITY_INFORMATION
+# define PROTECTED_DACL_SECURITY_INFORMATION 0x80000000L
+# endif
/*
* These are needed to dynamically load the ADVAPI DLL, which is not
* implemented under Windows 95 (and causes VIM to crash)
*/
-typedef DWORD (WINAPI *PSNSECINFO) (LPTSTR, enum SE_OBJECT_TYPE,
+typedef DWORD (WINAPI *PSNSECINFO) (LPSTR, enum SE_OBJECT_TYPE,
SECURITY_INFORMATION, PSID, PSID, PACL, PACL);
typedef DWORD (WINAPI *PGNSECINFO) (LPSTR, enum SE_OBJECT_TYPE,
SECURITY_INFORMATION, PSID *, PSID *, PACL *, PACL *,
PSECURITY_DESCRIPTOR *);
+# ifdef FEAT_MBYTE
+typedef DWORD (WINAPI *PSNSECINFOW) (LPWSTR, enum SE_OBJECT_TYPE,
+ SECURITY_INFORMATION, PSID, PSID, PACL, PACL);
+typedef DWORD (WINAPI *PGNSECINFOW) (LPWSTR, enum SE_OBJECT_TYPE,
+ SECURITY_INFORMATION, PSID *, PSID *, PACL *, PACL *,
+ PSECURITY_DESCRIPTOR *);
+# endif
static HANDLE advapi_lib = NULL; /* Handle for ADVAPI library */
static PSNSECINFO pSetNamedSecurityInfo;
static PGNSECINFO pGetNamedSecurityInfo;
+# ifdef FEAT_MBYTE
+static PSNSECINFOW pSetNamedSecurityInfoW;
+static PGNSECINFOW pGetNamedSecurityInfoW;
+# endif
#endif
typedef BOOL (WINAPI *PSETHANDLEINFORMATION)(HANDLE, DWORD, DWORD);
@@ -453,6 +467,42 @@
static BOOL allowPiping = FALSE;
static PSETHANDLEINFORMATION pSetHandleInformation;
+#ifdef HAVE_ACL
+/*
+ * Enables or disables the specified privilege.
+ */
+ static BOOL
+win32_enable_privilege(LPTSTR lpszPrivilege, BOOL bEnable)
+{
+ BOOL bResult;
+ LUID luid;
+ HANDLE hToken;
+ TOKEN_PRIVILEGES tokenPrivileges;
+
+ if (!OpenProcessToken(GetCurrentProcess(),
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
+ return FALSE;
+
+ if (!LookupPrivilegeValue(NULL, lpszPrivilege, &luid))
+ {
+ CloseHandle(hToken);
+ return FALSE;
+ }
+
+ tokenPrivileges.PrivilegeCount = 1;
+ tokenPrivileges.Privileges[0].Luid = luid;
+ tokenPrivileges.Privileges[0].Attributes = bEnable ?
+ SE_PRIVILEGE_ENABLED : 0;
+
+ bResult = AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges,
+ sizeof(TOKEN_PRIVILEGES), NULL, NULL);
+
+ CloseHandle(hToken);
+
+ return bResult && GetLastError() == ERROR_SUCCESS;
+}
+#endif
+
/*
* Set g_PlatformId to VER_PLATFORM_WIN32_NT (NT) or
* VER_PLATFORM_WIN32_WINDOWS (Win95).
@@ -492,14 +542,27 @@
"SetNamedSecurityInfoA");
pGetNamedSecurityInfo = (PGNSECINFO)GetProcAddress(advapi_lib,
"GetNamedSecurityInfoA");
+# ifdef FEAT_MBYTE
+ pSetNamedSecurityInfoW = (PSNSECINFOW)GetProcAddress(advapi_lib,
+ "SetNamedSecurityInfoW");
+ pGetNamedSecurityInfoW = (PGNSECINFOW)GetProcAddress(advapi_lib,
+ "GetNamedSecurityInfoW");
+# endif
if (pSetNamedSecurityInfo == NULL
- || pGetNamedSecurityInfo == NULL)
+ || pGetNamedSecurityInfo == NULL
+# ifdef FEAT_MBYTE
+ || pSetNamedSecurityInfoW == NULL
+ || pGetNamedSecurityInfoW == NULL
+# endif
+ )
{
/* If we can't get the function addresses, set advapi_lib
* to NULL so that we don't use them. */
FreeLibrary(advapi_lib);
advapi_lib = NULL;
}
+ /* Enable privilege for getting or setting SACLs. */
+ win32_enable_privilege(SE_SECURITY_NAME, TRUE);
}
}
#endif
@@ -2906,6 +2969,7 @@
return (vim_acl_T)NULL;
#else
struct my_acl *p = NULL;
+ DWORD err;
/* This only works on Windows NT and 2000. */
if (g_PlatformId == VER_PLATFORM_WIN32_NT && advapi_lib != NULL)
@@ -2913,23 +2977,82 @@
p = (struct my_acl *)alloc_clear((unsigned)sizeof(struct my_acl));
if (p != NULL)
{
- if (pGetNamedSecurityInfo(
- (LPTSTR)fname, // Abstract filename
- SE_FILE_OBJECT, // File Object
- // Retrieve the entire security descriptor.
- OWNER_SECURITY_INFORMATION |
- GROUP_SECURITY_INFORMATION |
- DACL_SECURITY_INFORMATION |
- SACL_SECURITY_INFORMATION,
- &p->pSidOwner, // Ownership information.
- &p->pSidGroup, // Group membership.
- &p->pDacl, // Discretionary information.
- &p->pSacl, // For auditing purposes.
- &p->pSecurityDescriptor
- ) != ERROR_SUCCESS)
+# ifdef FEAT_MBYTE
+ WCHAR *wn = NULL;
+
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ wn = enc_to_utf16(fname, NULL);
+ if (wn != NULL)
{
- mch_free_acl((vim_acl_T)p);
- p = NULL;
+ /* Try to retrieve the entire security descriptor. */
+ err = pGetNamedSecurityInfoW(
+ wn, // Abstract filename
+ SE_FILE_OBJECT, // File Object
+ OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION |
+ SACL_SECURITY_INFORMATION,
+ &p->pSidOwner, // Ownership information.
+ &p->pSidGroup, // Group membership.
+ &p->pDacl, // Discretionary information.
+ &p->pSacl, // For auditing purposes.
+ &p->pSecurityDescriptor);
+ if (err == ERROR_ACCESS_DENIED ||
+ err == ERROR_PRIVILEGE_NOT_HELD)
+ {
+ /* Retrieve only DACL. */
+ (void)pGetNamedSecurityInfoW(
+ wn,
+ SE_FILE_OBJECT,
+ DACL_SECURITY_INFORMATION,
+ NULL,
+ NULL,
+ &p->pDacl,
+ NULL,
+ &p->pSecurityDescriptor);
+ }
+ if (p->pSecurityDescriptor == NULL)
+ {
+ mch_free_acl((vim_acl_T)p);
+ p = NULL;
+ }
+ vim_free(wn);
+ }
+ else
+# endif
+ {
+ /* Try to retrieve the entire security descriptor. */
+ err = pGetNamedSecurityInfo(
+ (LPSTR)fname, // Abstract filename
+ SE_FILE_OBJECT, // File Object
+ OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION |
+ SACL_SECURITY_INFORMATION,
+ &p->pSidOwner, // Ownership information.
+ &p->pSidGroup, // Group membership.
+ &p->pDacl, // Discretionary information.
+ &p->pSacl, // For auditing purposes.
+ &p->pSecurityDescriptor);
+ if (err == ERROR_ACCESS_DENIED ||
+ err == ERROR_PRIVILEGE_NOT_HELD)
+ {
+ /* Retrieve only DACL. */
+ (void)pGetNamedSecurityInfo(
+ (LPSTR)fname,
+ SE_FILE_OBJECT,
+ DACL_SECURITY_INFORMATION,
+ NULL,
+ NULL,
+ &p->pDacl,
+ NULL,
+ &p->pSecurityDescriptor);
+ }
+ if (p->pSecurityDescriptor == NULL)
+ {
+ mch_free_acl((vim_acl_T)p);
+ p = NULL;
+ }
}
}
}
@@ -2938,6 +3061,29 @@
#endif
}
+#ifdef HAVE_ACL
+/*
+ * Check if "acl" contains inherited ACE.
+ */
+ static BOOL
+is_acl_inherited(PACL acl)
+{
+ DWORD i;
+ ACL_SIZE_INFORMATION acl_info;
+ PACCESS_ALLOWED_ACE ace;
+
+ acl_info.AceCount = 0;
+ GetAclInformation(acl, &acl_info, sizeof(acl_info), AclSizeInformation);
+ for (i = 0; i < acl_info.AceCount; i++)
+ {
+ GetAce(acl, i, (LPVOID *)&ace);
+ if (ace->Header.AceFlags & INHERITED_ACE)
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+
/*
* Set the ACL of file "fname" to "acl" (unless it's NULL).
* Errors are ignored.
@@ -2948,21 +3094,61 @@
{
#ifdef HAVE_ACL
struct my_acl *p = (struct my_acl *)acl;
+ SECURITY_INFORMATION sec_info = 0;
if (p != NULL && advapi_lib != NULL)
- (void)pSetNamedSecurityInfo(
- (LPTSTR)fname, // Abstract filename
- SE_FILE_OBJECT, // File Object
- // Retrieve the entire security descriptor.
- OWNER_SECURITY_INFORMATION |
- GROUP_SECURITY_INFORMATION |
- DACL_SECURITY_INFORMATION |
- SACL_SECURITY_INFORMATION,
- p->pSidOwner, // Ownership information.
- p->pSidGroup, // Group membership.
- p->pDacl, // Discretionary information.
- p->pSacl // For auditing purposes.
- );
+ {
+# ifdef FEAT_MBYTE
+ WCHAR *wn = NULL;
+# endif
+
+ /* Set security flags */
+ if (p->pSidOwner)
+ sec_info |= OWNER_SECURITY_INFORMATION;
+ if (p->pSidGroup)
+ sec_info |= GROUP_SECURITY_INFORMATION;
+ if (p->pDacl)
+ {
+ sec_info |= DACL_SECURITY_INFORMATION;
+ /* Do not inherit its parent's DACL.
+ * If the DACL is inherited, Cygwin permissions would be changed.
+ */
+ if (!is_acl_inherited(p->pDacl))
+ sec_info |= PROTECTED_DACL_SECURITY_INFORMATION;
+ }
+ if (p->pSacl)
+ sec_info |= SACL_SECURITY_INFORMATION;
+
+# ifdef FEAT_MBYTE
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ wn = enc_to_utf16(fname, NULL);
+ if (wn != NULL)
+ {
+ (void)pSetNamedSecurityInfoW(
+ wn, // Abstract filename
+ SE_FILE_OBJECT, // File Object
+ sec_info,
+ p->pSidOwner, // Ownership information.
+ p->pSidGroup, // Group membership.
+ p->pDacl, // Discretionary information.
+ p->pSacl // For auditing purposes.
+ );
+ vim_free(wn);
+ }
+ else
+# endif
+ {
+ (void)pSetNamedSecurityInfo(
+ (LPSTR)fname, // Abstract filename
+ SE_FILE_OBJECT, // File Object
+ sec_info,
+ p->pSidOwner, // Ownership information.
+ p->pSidGroup, // Group membership.
+ p->pDacl, // Discretionary information.
+ p->pSacl // For auditing purposes.
+ );
+ }
+ }
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment