2

I'm trying to use the CreateSymbolicLinkW() function (from Kernel32.dll) to create a symlink.

On the respective machine (Win7 Pro x64 SP1):

  • UAC is enabled (=processes of users with local admin privileges are by default NOT elevated)
  • I've granted all authenticated users the "create symbolic link" user rights assignment (through a group policy with Computer -> Windows Settings -> Security -> Local Policies -> User Rights Assignment -> Create Symbolic Link = Authenticated Users)
  • I've enabled all possible symlink evaluation types (again through a Group Policy setting). (to confirm "fsutil behavior query SymlinkEvaluation" returns: "Local to local symbolic links are enabled. Local to remote symbolic links are enabled. Remote to local symbolic links are enabled. Remote to remote symbolic links are enabled."

the Situation now is:

  • when I run CreateSymbolicLinkW() as a NON-ADMIN user in an UNELEVATED process, it WORKS (symlink created)
  • when I run CreateSymbolicLinkW() as an ADMIN user in a ELEVATED process, it WORKS (symlink created)
  • when I run CreateSymbolicLinkW() as an ADMIN (!) user in a UNELEVATED (!) process, it DOES NOT WORK

The last case is the actual problem. The error returned by GetLastError is: 1314 (= "a required privilege is not held by the client").

Why is it failing for the Admin user in an unelevated process, while it works for any non-admin user in an unelevated shell?

My code is intended to be run by any type of user, preferably in an unelevated process. Asking admin users to elevate the process as a workaround is something that I'd like to avoid at any circumstance.

The same behavior can also be reproduced with the MKLINK command in the Windows shell btw (fails for admin users in a non-elevated shell while it works for all non-admin users in a non-elevated shell).

Sample Code with Python 2.7:

import ctypes
CreateSymbolicLinkW = ctypes.WinDLL("Kernel32").CreateSymbolicLinkW
CreateSymbolicLinkW(u"c:\\linktest\\testlink.txt", u"c:\\linktest\\testtarget.txt",0)
print(ctypes.WinDLL("Kernel32").GetLastError())
Nimantha
  • 6,405
  • 6
  • 28
  • 69
Chris
  • 567
  • 6
  • 24
  • Can you show some code? – selbie Mar 15 '15 at 17:38
  • @selbie the easiest way to reproduce the probem is: 1.) grant all users on the machine the permission to create symlinks (secpol.msc -> local policies -> user rights assignment -> set "create symbolic link" to "authenticated users" 2.) make sure UAC is enabled on the machine 3.) open a non-elevated shell under a user who has admin privileges and in there run: mklink "%userprofile%\testlink.txt" "%userprofile%\testtarget.txt" You will receive a insufficient privilege error. – Chris Mar 15 '15 at 18:03
  • 1
    FWIW, your error handling in the ctypes code is totally bogus. You have to test return values. And the call to `GetLastError` that you make is wrong too. Read the docs (https://docs.python.org/2/library/ctypes.html) and look for the discussion around `get_last_error`. – David Heffernan Mar 15 '15 at 19:50

1 Answers1

6

The behavior you observe is due to UAC and the restricted token an admin user is given by default. This token is created automatically by taking the normal admin user's token and filtering it to remove various administrator privileges.

You can see what privileges your token has by running the command whoami /priv in a DOS prompt. From an elevated prompt, your token will have a much larger set of privileges than from an un-elevated prompt, including the Create symbolic links privilege.

Unfortunately I don't believe there's a way around this, since this is exactly how UAC is designed to operate. I don't think there's any way to control how the admin token is filtered, which is the key issue - other than disabling UAC altogether.

Jonathan Potter
  • 36,172
  • 4
  • 64
  • 79
  • The slightly odd thing is that the OP says it works for non-admin users. According to the documentation, and previous questions, having SeCreateSymbolicLinkPrivilege should cause UAC to treat the user as an administrator and create a split token. – Harry Johnston Mar 15 '15 at 22:09
  • 3
    @HarryJohnston: Non-admin users do not get the split token as far as I know, so they get the privileges assigned to them. There's nothing special about SeCreateSymbolicLinkPrivilege; if a user has been given that privilege they'll have it - it's just that for admin users, the token filtering is *removing* it. That's my understanding anyway. – Jonathan Potter Mar 15 '15 at 22:10
  • In [Windows Vista Application Development Requirements for User Account Control Compatibility](https://msdn.microsoft.com/en-us/library/bb530410.aspx?f=255&MSPPError=-2147217396) it says "Windows will create two access tokens for the user if [...] The user's account contains any privileges other than those of a standard user account." However, looking at the relevant questions again, I don't see any evidence that this was ever the actual behaviour. And I think I may have seen a different list elsewhere of "privileges that trigger UAC" so probably that article is just mistaken. – Harry Johnston Mar 15 '15 at 22:21
  • hi, thanks for the hint. The problem is indeed that the unelevated process doesn't have the "SeCreateSymbolicLinkPrivilege". I assume there's no workaround? :( – Chris Mar 16 '15 at 09:47