2010-01-19 7 views
5

Je souhaite déterminer par programme si l'utilisateur (ou le processus) actuel a accès à la création de liens symboliques. Sous Windows (Vista et version ultérieure), il est impossible de créer un lien symbolique sans le SeCreateSymbolicLinkPrivilege. Par défaut, ce lien est uniquement attribué aux administrateurs. Si vous tentez de créer un lien symbolique sans ce privilège, une erreur Windows 1314 (Un privilège requis n'est pas détenu par le client) se produit.Détermine si le processus Windows a le privilège de créer un lien symbolique

Pour illustrer cette restriction, j'ai créé une nouvelle installation de Windows, connecté en tant que compte Administrateur initial (restreint via le contrôle de compte d'utilisateur) et incapable de créer un lien symbolique dans le répertoire de base.

Command Prompt demonstrates mklink fails due to insufficient privilege

Après avoir exécuté l'invite de commande en tant qu'administrateur ou la désactivation de l'UAC, cette commande exécute sans erreur.

Selon this article, "chaque processus exécuté pour le compte de l'utilisateur a une copie du jeton [d'accès]". J'ai donc créé a Python script to query for the permissions. Pour plus de commodité et de postérité, j'inclus un extrait ci-dessous.

L'idée derrière le script est d'énumérer tous les privilèges et de déterminer si le processus a le privilège requis. Malheureusement, je trouve que le processus actuel n'a pas le privilège désiré, même lorsqu'il peut créer des liens symboliques.

Je suppose que le problème est que même si les privilèges de l'utilisateur actuel n'incluent pas explicitement le privilège, son appartenance au groupe lui procure ce privilège. En bref, comment puis-je déterminer si un processus donné aura le privilège de créer des liens symboliques (sans essayer d'en créer un)? Un exemple en C ou C++ ou en Python est préféré, bien que tout ce qui utilise l'API Windows convienne.

def get_process_token(): 
    token = wintypes.HANDLE() 
    TOKEN_ALL_ACCESS = 0xf01ff 
    res = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, token) 
    if not res > 0: raise RuntimeError("Couldn't get process token") 
    return token 

def get_privilege_information(): 
    # first call with zero length to determine what size buffer we need 

    return_length = wintypes.DWORD() 
    params = [ 
     get_process_token(), 
     TOKEN_INFORMATION_CLASS.TokenPrivileges, 
     None, 
     0, 
     return_length, 
     ] 

    res = GetTokenInformation(*params) 

    # assume we now have the necessary length in return_length 

    buffer = ctypes.create_string_buffer(return_length.value) 
    params[2] = buffer 
    params[3] = return_length.value 

    res = GetTokenInformation(*params) 
    assert res > 0, "Error in second GetTokenInformation (%d)" % res 

    privileges = ctypes.cast(buffer, ctypes.POINTER(TOKEN_PRIVILEGES)).contents 
    return privileges 

privileges = get_privilege_information() 
print("found {0} privileges".format(privileges.count)) 
map(print, privileges) 
+0

Windows a des liens symboliques? –

+2

Quel genre de lien symbolique essayez-vous de créer? Il y a un tas de choses qui peuvent être considérées comme des liens symboliques dans Windows - points de jonction de systèmes de fichiers, liens matériels de système de fichiers, liens symboliques de gestionnaire d'objet, etc. Je crois que vous avez besoin du privilège SeCreateSymbolicLink pour créer des liens symboliques de gestionnaire d'objet. –

+0

J'essaie de créer des liens symboliques basés sur le point de jonction du système de fichiers, tels que ceux créés par CreateSymbolicLink. –

Répondre

4

J'ai trouvé une solution. Le code Python suivant est un script entièrement fonctionnel sous Python 2.6 ou 3.1 qui montre comment déterminer un privilège pour créer des liens symboliques. Exécuter cela sous le compte administrateur répond avec succès, et l'exécuter sous le compte Invité répond à un échec. Notez que le premier 3/4 du script est principalement des définitions d'API. Le travail original commence avec get_process_token().

from __future__ import print_function 
import ctypes 
from ctypes import wintypes 

GetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess 
GetCurrentProcess.restype = wintypes.HANDLE 
OpenProcessToken = ctypes.windll.advapi32.OpenProcessToken 
OpenProcessToken.argtypes = (wintypes.HANDLE, wintypes.DWORD, ctypes.POINTER(wintypes.HANDLE)) 
OpenProcessToken.restype = wintypes.BOOL 

class LUID(ctypes.Structure): 
    _fields_ = [ 
     ('low_part', wintypes.DWORD), 
     ('high_part', wintypes.LONG), 
     ] 

    def __eq__(self, other): 
     return (
      self.high_part == other.high_part and 
      self.low_part == other.low_part 
      ) 

    def __ne__(self, other): 
     return not (self==other) 

LookupPrivilegeValue = ctypes.windll.advapi32.LookupPrivilegeValueW 
LookupPrivilegeValue.argtypes = (
    wintypes.LPWSTR, # system name 
    wintypes.LPWSTR, # name 
    ctypes.POINTER(LUID), 
    ) 
LookupPrivilegeValue.restype = wintypes.BOOL 

class TOKEN_INFORMATION_CLASS: 
    TokenUser = 1 
    TokenGroups = 2 
    TokenPrivileges = 3 
    # ... see http://msdn.microsoft.com/en-us/library/aa379626%28VS.85%29.aspx 

SE_PRIVILEGE_ENABLED_BY_DEFAULT = (0x00000001) 
SE_PRIVILEGE_ENABLED   = (0x00000002) 
SE_PRIVILEGE_REMOVED   = (0x00000004) 
SE_PRIVILEGE_USED_FOR_ACCESS = (0x80000000) 

class LUID_AND_ATTRIBUTES(ctypes.Structure): 
    _fields_ = [ 
     ('LUID', LUID), 
     ('attributes', wintypes.DWORD), 
     ] 

    def is_enabled(self): 
     return bool(self.attributes & SE_PRIVILEGE_ENABLED) 

    def enable(self): 
     self.attributes |= SE_PRIVILEGE_ENABLED 

    def get_name(self): 
     size = wintypes.DWORD(10240) 
     buf = ctypes.create_unicode_buffer(size.value) 
     res = LookupPrivilegeName(None, self.LUID, buf, size) 
     if res == 0: raise RuntimeError 
     return buf[:size.value] 

    def __str__(self): 
     res = self.get_name() 
     if self.is_enabled(): res += ' (enabled)' 
     return res 

LookupPrivilegeName = ctypes.windll.advapi32.LookupPrivilegeNameW 
LookupPrivilegeName.argtypes = (
    wintypes.LPWSTR, # lpSystemName 
    ctypes.POINTER(LUID), # lpLuid 
    wintypes.LPWSTR, # lpName 
    ctypes.POINTER(wintypes.DWORD), #cchName 
    ) 
LookupPrivilegeName.restype = wintypes.BOOL 

class TOKEN_PRIVILEGES(ctypes.Structure): 
    _fields_ = [ 
     ('count', wintypes.DWORD), 
     ('privileges', LUID_AND_ATTRIBUTES*0), 
     ] 

    def get_array(self): 
     array_type = LUID_AND_ATTRIBUTES*self.count 
     privileges = ctypes.cast(self.privileges, ctypes.POINTER(array_type)).contents 
     return privileges 

    def __iter__(self): 
     return iter(self.get_array()) 

PTOKEN_PRIVILEGES = ctypes.POINTER(TOKEN_PRIVILEGES) 

GetTokenInformation = ctypes.windll.advapi32.GetTokenInformation 
GetTokenInformation.argtypes = [ 
    wintypes.HANDLE, # TokenHandle 
    ctypes.c_uint, # TOKEN_INFORMATION_CLASS value 
    ctypes.c_void_p, # TokenInformation 
    wintypes.DWORD, # TokenInformationLength 
    ctypes.POINTER(wintypes.DWORD), # ReturnLength 
    ] 
GetTokenInformation.restype = wintypes.BOOL 

# http://msdn.microsoft.com/en-us/library/aa375202%28VS.85%29.aspx 
AdjustTokenPrivileges = ctypes.windll.advapi32.AdjustTokenPrivileges 
AdjustTokenPrivileges.restype = wintypes.BOOL 
AdjustTokenPrivileges.argtypes = [ 
    wintypes.HANDLE,    # TokenHandle 
    wintypes.BOOL,     # DisableAllPrivileges 
    PTOKEN_PRIVILEGES,    # NewState (optional) 
    wintypes.DWORD,     # BufferLength of PreviousState 
    PTOKEN_PRIVILEGES,    # PreviousState (out, optional) 
    ctypes.POINTER(wintypes.DWORD), # ReturnLength 
    ] 

def get_process_token(): 
    """ 
    Get the current process token 
    """ 
    token = wintypes.HANDLE() 
    TOKEN_ALL_ACCESS = 0xf01ff 
    res = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, token) 
    if not res > 0: raise RuntimeError("Couldn't get process token") 
    return token 

def get_symlink_luid(): 
    """ 
    Get the LUID for the SeCreateSymbolicLinkPrivilege 
    """ 
    symlink_luid = LUID() 
    res = LookupPrivilegeValue(None, "SeCreateSymbolicLinkPrivilege", symlink_luid) 
    if not res > 0: raise RuntimeError("Couldn't lookup privilege value") 
    return symlink_luid 

def get_privilege_information(): 
    """ 
    Get all privileges associated with the current process. 
    """ 
    # first call with zero length to determine what size buffer we need 

    return_length = wintypes.DWORD() 
    params = [ 
     get_process_token(), 
     TOKEN_INFORMATION_CLASS.TokenPrivileges, 
     None, 
     0, 
     return_length, 
     ] 

    res = GetTokenInformation(*params) 

    # assume we now have the necessary length in return_length 

    buffer = ctypes.create_string_buffer(return_length.value) 
    params[2] = buffer 
    params[3] = return_length.value 

    res = GetTokenInformation(*params) 
    assert res > 0, "Error in second GetTokenInformation (%d)" % res 

    privileges = ctypes.cast(buffer, ctypes.POINTER(TOKEN_PRIVILEGES)).contents 
    return privileges 

def report_privilege_information(): 
    """ 
    Report all privilege information assigned to the current process. 
    """ 
    privileges = get_privilege_information() 
    print("found {0} privileges".format(privileges.count)) 
    tuple(map(print, privileges)) 

def enable_symlink_privilege(): 
    """ 
    Try to assign the symlink privilege to the current process token. 
    Return True if the assignment is successful. 
    """ 
    # create a space in memory for a TOKEN_PRIVILEGES structure 
    # with one element 
    size = ctypes.sizeof(TOKEN_PRIVILEGES) 
    size += ctypes.sizeof(LUID_AND_ATTRIBUTES) 
    buffer = ctypes.create_string_buffer(size) 
    tp = ctypes.cast(buffer, ctypes.POINTER(TOKEN_PRIVILEGES)).contents 
    tp.count = 1 
    tp.get_array()[0].enable() 
    tp.get_array()[0].LUID = get_symlink_luid() 
    token = get_process_token() 
    res = AdjustTokenPrivileges(token, False, tp, 0, None, None) 
    if res == 0: 
     raise RuntimeError("Error in AdjustTokenPrivileges") 

    ERROR_NOT_ALL_ASSIGNED = 1300 
    return ctypes.windll.kernel32.GetLastError() != ERROR_NOT_ALL_ASSIGNED 

def main(): 
    assigned = enable_symlink_privilege() 
    msg = ['failure', 'success'][assigned] 

    print("Symlink privilege assignment completed with {0}".format(msg)) 

if __name__ == '__main__': main() 
Questions connexes