2010-01-19 4 views
5

Я хочу программным образом определить, имеет ли текущий пользователь (или процесс) доступ к созданию символических ссылок. В Windows (Vista и выше) невозможно создать символическую ссылку без SeCreateSymbolicLinkPrivilege, и по умолчанию это назначается только администраторам. Если вы попытаетесь создать символическую ссылку без этой привилегии, произойдет ошибка Windows 1314 (требуемая привилегия не удерживается клиентом).Определите, имеет ли Windows-процесс право создавать символическую ссылку

Чтобы продемонстрировать это ограничение, я создал чистую установку Windows, зарегистрированную как начальную учетную запись администратора (ограниченную через UAC) и не смог создать символическую ссылку в домашнем каталоге.

Command Prompt demonstrates mklink fails due to insufficient privilege

После запуска командной строки от имени администратора или отключение контроля учетных записей, эта команда выполняется без ошибок.

Согласно this article, «каждый процесс, выполняемый от имени пользователя, имеет копию маркера [доступа]».

Итак, я создал a Python script to query for the permissions. Для удобства и потомства я включаю выдержку ниже.

Идея сценария заключается в перечислении всех привилегий и определении того, имеет ли процесс требуемые привилегии. К сожалению, я обнаружил, что текущий процесс на самом деле не имеет желаемой привилегии, даже когда он может создавать символические ссылки.

Я подозреваю, что проблема заключается в том, что, хотя привилегии текущего пользователя явно не включают эту привилегию, членство в группе действительно дает эту привилегию.

Вкратце, как я могу определить, будет ли данный процесс иметь привилегию создавать символические ссылки (не пытаясь создать его)? Примером может служить пример на C или C++ или Python, хотя все, что использует Windows API, будет подходящим.

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 есть символические ссылки? –

+2

Какую символическую ссылку вы пытаетесь создать? Существует множество разных вещей, которые могут считаться символическими ссылками в Windows - точки соединения файловой системы, жесткие ссылки файловой системы, символические ссылки диспетчера объектов и т. Д. Я считаю, что вам нужна только привилегия SeCreateSymbolicLink для создания символических ссылок диспетчера объектов. –

+0

Я пытаюсь создать символические ссылки на основе слайдов на файловой системе, такие как созданные CreateSymbolicLink. –

ответ

4

Я нашел решение. Следующий код Python является полнофункциональным скриптом под Python 2.6 или 3.1, который демонстрирует, как можно определить привилегию создания символических ссылок. Выполнение этого под учетной записью администратора отвечает успешно, и запуск под учетной записью гостя отвечает сбоем.

Обратите внимание, что первые 3/4 скрипта являются в основном определениями API. Новая работа начинается с 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() 
Смежные вопросы