[PATCH setup 06/11] Enable SeCreateSymbolicLink privilege

Jon Turney jon.turney@dronecode.org.uk
Tue Aug 10 17:02:23 GMT 2021


I'm not sure if SeCreateSymbolicLink privilege can get removed by UAC
filtering, but to make sure to enable it, if we can.

Also report if it's available to log.
---
 win32.cc | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 win32.h  |  2 ++
 2 files changed, 60 insertions(+)

diff --git a/win32.cc b/win32.cc
index 8ee424f..6455384 100644
--- a/win32.cc
+++ b/win32.cc
@@ -280,6 +280,28 @@ NTSecurity::setBackupPrivileges ()
     }
 }
 
+void
+NTSecurity::setSymlinkPrivilege ()
+{
+  LUID symlink;
+  if (!LookupPrivilegeValue (NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &symlink))
+    NoteFailedAPI ("LookupPrivilegeValue");
+
+  PTOKEN_PRIVILEGES new_priv;
+  new_priv = (PTOKEN_PRIVILEGES) alloca (sizeof (TOKEN_PRIVILEGES));
+  new_priv->PrivilegeCount = 1;
+  new_priv->Privileges[0].Luid = symlink;
+  new_priv->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+  if (!AdjustTokenPrivileges (token.theHANDLE (), FALSE, new_priv,
+                              0, NULL, NULL))
+    NoteFailedAPI ("AdjustTokenPrivileges");
+  else if (GetLastError () == ERROR_NOT_ALL_ASSIGNED)
+    Log (LOG_TIMESTAMP) << "User has NO symlink creation right" << endLog;
+  else
+    Log (LOG_TIMESTAMP) << "User has symlink creation right" << endLog;
+}
+
 void
 NTSecurity::resetPrimaryGroup ()
 {
@@ -321,6 +343,9 @@ NTSecurity::setDefaultSecurity (bool isAdmin)
   /* Set backup and restore privileges if available. */
   setBackupPrivileges ();
 
+  /* Set symlink creation privilege, if available. */
+  setSymlinkPrivilege ();
+
   /* If initializing the well-known SIDs didn't work, we're finished here. */
   if (!wellKnownSIDsinitialized ())
     return;
@@ -371,6 +396,39 @@ NTSecurity::isRunAsAdmin ()
   return (is_run_as_admin == TRUE);
 }
 
+bool
+NTSecurity::hasSymlinkCreationRights ()
+{
+  LUID symlink;
+  if (!LookupPrivilegeValue (NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &symlink))
+    {
+      NoteFailedAPI ("LookupPrivilegeValue");
+      return FALSE;
+    }
+
+  DWORD size;
+  GetTokenInformation (token.theHANDLE (), TokenPrivileges, NULL, 0, &size);
+  /* Will fail ERROR_INSUFFICIENT_BUFFER, but updates size */
+
+  TOKEN_PRIVILEGES *privileges = (TOKEN_PRIVILEGES *)alloca(size);
+  if (!GetTokenInformation (token.theHANDLE (), TokenPrivileges, privileges,
+                            size, &size))
+    {
+      NoteFailedAPI ("GetTokenInformation(privileges)");
+      return FALSE;
+    }
+
+  unsigned int i;
+  for (i = 0; i < privileges->PrivilegeCount; i++)
+    {
+      if (memcmp(&privileges->Privileges[i].Luid, &symlink, sizeof(LUID)) == 0)
+        {
+          return (privileges->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED);
+        }
+    }
+
+  return FALSE;
+}
 
 VersionInfo::VersionInfo ()
 {
diff --git a/win32.h b/win32.h
index daebf2e..e498077 100644
--- a/win32.h
+++ b/win32.h
@@ -132,12 +132,14 @@ public:
   void initialiseWellKnownSIDs ();
   void setDefaultSecurity(bool isAdmin);
   bool isRunAsAdmin ();
+  bool hasSymlinkCreationRights ();
 private:
   void NoteFailedAPI (const std::string &);
   bool wellKnownSIDsinitialized () const { return _wellKnownSIDsinitialized; }
   void wellKnownSIDsinitialized (bool b) { _wellKnownSIDsinitialized = b; }
   void setDefaultDACL ();
   void setBackupPrivileges ();
+  void setSymlinkPrivilege ();
 
   SIDWrapper nullSID, everyOneSID, administratorsSID, usersSID,
 	     cr_ownerSID, cr_groupSID;
-- 
2.32.0



More information about the Cygwin-apps mailing list