_winapi.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. """
  2. Windows API functions implemented as ctypes functions and classes as found
  3. in jaraco.windows (3.4.1).
  4. If you encounter issues with this module, please consider reporting the issues
  5. in jaraco.windows and asking the author to port the fixes back here.
  6. """
  7. import sys
  8. import ctypes.wintypes
  9. from paramiko.py3compat import u, builtins
  10. ######################
  11. # jaraco.windows.error
  12. def format_system_message(errno):
  13. """
  14. Call FormatMessage with a system error number to retrieve
  15. the descriptive error message.
  16. """
  17. # first some flags used by FormatMessageW
  18. ALLOCATE_BUFFER = 0x100
  19. FROM_SYSTEM = 0x1000
  20. # Let FormatMessageW allocate the buffer (we'll free it below)
  21. # Also, let it know we want a system error message.
  22. flags = ALLOCATE_BUFFER | FROM_SYSTEM
  23. source = None
  24. message_id = errno
  25. language_id = 0
  26. result_buffer = ctypes.wintypes.LPWSTR()
  27. buffer_size = 0
  28. arguments = None
  29. bytes = ctypes.windll.kernel32.FormatMessageW(
  30. flags,
  31. source,
  32. message_id,
  33. language_id,
  34. ctypes.byref(result_buffer),
  35. buffer_size,
  36. arguments,
  37. )
  38. # note the following will cause an infinite loop if GetLastError
  39. # repeatedly returns an error that cannot be formatted, although
  40. # this should not happen.
  41. handle_nonzero_success(bytes)
  42. message = result_buffer.value
  43. ctypes.windll.kernel32.LocalFree(result_buffer)
  44. return message
  45. class WindowsError(builtins.WindowsError):
  46. """more info about errors at
  47. http://msdn.microsoft.com/en-us/library/ms681381(VS.85).aspx"""
  48. def __init__(self, value=None):
  49. if value is None:
  50. value = ctypes.windll.kernel32.GetLastError()
  51. strerror = format_system_message(value)
  52. if sys.version_info > (3, 3):
  53. args = 0, strerror, None, value
  54. else:
  55. args = value, strerror
  56. super(WindowsError, self).__init__(*args)
  57. @property
  58. def message(self):
  59. return self.strerror
  60. @property
  61. def code(self):
  62. return self.winerror
  63. def __str__(self):
  64. return self.message
  65. def __repr__(self):
  66. return "{self.__class__.__name__}({self.winerror})".format(**vars())
  67. def handle_nonzero_success(result):
  68. if result == 0:
  69. raise WindowsError()
  70. ###########################
  71. # jaraco.windows.api.memory
  72. GMEM_MOVEABLE = 0x2
  73. GlobalAlloc = ctypes.windll.kernel32.GlobalAlloc
  74. GlobalAlloc.argtypes = ctypes.wintypes.UINT, ctypes.c_size_t
  75. GlobalAlloc.restype = ctypes.wintypes.HANDLE
  76. GlobalLock = ctypes.windll.kernel32.GlobalLock
  77. GlobalLock.argtypes = (ctypes.wintypes.HGLOBAL,)
  78. GlobalLock.restype = ctypes.wintypes.LPVOID
  79. GlobalUnlock = ctypes.windll.kernel32.GlobalUnlock
  80. GlobalUnlock.argtypes = (ctypes.wintypes.HGLOBAL,)
  81. GlobalUnlock.restype = ctypes.wintypes.BOOL
  82. GlobalSize = ctypes.windll.kernel32.GlobalSize
  83. GlobalSize.argtypes = (ctypes.wintypes.HGLOBAL,)
  84. GlobalSize.restype = ctypes.c_size_t
  85. CreateFileMapping = ctypes.windll.kernel32.CreateFileMappingW
  86. CreateFileMapping.argtypes = [
  87. ctypes.wintypes.HANDLE,
  88. ctypes.c_void_p,
  89. ctypes.wintypes.DWORD,
  90. ctypes.wintypes.DWORD,
  91. ctypes.wintypes.DWORD,
  92. ctypes.wintypes.LPWSTR,
  93. ]
  94. CreateFileMapping.restype = ctypes.wintypes.HANDLE
  95. MapViewOfFile = ctypes.windll.kernel32.MapViewOfFile
  96. MapViewOfFile.restype = ctypes.wintypes.HANDLE
  97. UnmapViewOfFile = ctypes.windll.kernel32.UnmapViewOfFile
  98. UnmapViewOfFile.argtypes = (ctypes.wintypes.HANDLE,)
  99. RtlMoveMemory = ctypes.windll.kernel32.RtlMoveMemory
  100. RtlMoveMemory.argtypes = (ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t)
  101. ctypes.windll.kernel32.LocalFree.argtypes = (ctypes.wintypes.HLOCAL,)
  102. #####################
  103. # jaraco.windows.mmap
  104. class MemoryMap(object):
  105. """
  106. A memory map object which can have security attributes overridden.
  107. """
  108. def __init__(self, name, length, security_attributes=None):
  109. self.name = name
  110. self.length = length
  111. self.security_attributes = security_attributes
  112. self.pos = 0
  113. def __enter__(self):
  114. p_SA = (
  115. ctypes.byref(self.security_attributes)
  116. if self.security_attributes
  117. else None
  118. )
  119. INVALID_HANDLE_VALUE = -1
  120. PAGE_READWRITE = 0x4
  121. FILE_MAP_WRITE = 0x2
  122. filemap = ctypes.windll.kernel32.CreateFileMappingW(
  123. INVALID_HANDLE_VALUE,
  124. p_SA,
  125. PAGE_READWRITE,
  126. 0,
  127. self.length,
  128. u(self.name),
  129. )
  130. handle_nonzero_success(filemap)
  131. if filemap == INVALID_HANDLE_VALUE:
  132. raise Exception("Failed to create file mapping")
  133. self.filemap = filemap
  134. self.view = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0)
  135. return self
  136. def seek(self, pos):
  137. self.pos = pos
  138. def write(self, msg):
  139. assert isinstance(msg, bytes)
  140. n = len(msg)
  141. if self.pos + n >= self.length: # A little safety.
  142. raise ValueError("Refusing to write %d bytes" % n)
  143. dest = self.view + self.pos
  144. length = ctypes.c_size_t(n)
  145. ctypes.windll.kernel32.RtlMoveMemory(dest, msg, length)
  146. self.pos += n
  147. def read(self, n):
  148. """
  149. Read n bytes from mapped view.
  150. """
  151. out = ctypes.create_string_buffer(n)
  152. source = self.view + self.pos
  153. length = ctypes.c_size_t(n)
  154. ctypes.windll.kernel32.RtlMoveMemory(out, source, length)
  155. self.pos += n
  156. return out.raw
  157. def __exit__(self, exc_type, exc_val, tb):
  158. ctypes.windll.kernel32.UnmapViewOfFile(self.view)
  159. ctypes.windll.kernel32.CloseHandle(self.filemap)
  160. #############################
  161. # jaraco.windows.api.security
  162. # from WinNT.h
  163. READ_CONTROL = 0x00020000
  164. STANDARD_RIGHTS_REQUIRED = 0x000F0000
  165. STANDARD_RIGHTS_READ = READ_CONTROL
  166. STANDARD_RIGHTS_WRITE = READ_CONTROL
  167. STANDARD_RIGHTS_EXECUTE = READ_CONTROL
  168. STANDARD_RIGHTS_ALL = 0x001F0000
  169. # from NTSecAPI.h
  170. POLICY_VIEW_LOCAL_INFORMATION = 0x00000001
  171. POLICY_VIEW_AUDIT_INFORMATION = 0x00000002
  172. POLICY_GET_PRIVATE_INFORMATION = 0x00000004
  173. POLICY_TRUST_ADMIN = 0x00000008
  174. POLICY_CREATE_ACCOUNT = 0x00000010
  175. POLICY_CREATE_SECRET = 0x00000020
  176. POLICY_CREATE_PRIVILEGE = 0x00000040
  177. POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080
  178. POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100
  179. POLICY_AUDIT_LOG_ADMIN = 0x00000200
  180. POLICY_SERVER_ADMIN = 0x00000400
  181. POLICY_LOOKUP_NAMES = 0x00000800
  182. POLICY_NOTIFICATION = 0x00001000
  183. POLICY_ALL_ACCESS = (
  184. STANDARD_RIGHTS_REQUIRED
  185. | POLICY_VIEW_LOCAL_INFORMATION
  186. | POLICY_VIEW_AUDIT_INFORMATION
  187. | POLICY_GET_PRIVATE_INFORMATION
  188. | POLICY_TRUST_ADMIN
  189. | POLICY_CREATE_ACCOUNT
  190. | POLICY_CREATE_SECRET
  191. | POLICY_CREATE_PRIVILEGE
  192. | POLICY_SET_DEFAULT_QUOTA_LIMITS
  193. | POLICY_SET_AUDIT_REQUIREMENTS
  194. | POLICY_AUDIT_LOG_ADMIN
  195. | POLICY_SERVER_ADMIN
  196. | POLICY_LOOKUP_NAMES
  197. )
  198. POLICY_READ = (
  199. STANDARD_RIGHTS_READ
  200. | POLICY_VIEW_AUDIT_INFORMATION
  201. | POLICY_GET_PRIVATE_INFORMATION
  202. )
  203. POLICY_WRITE = (
  204. STANDARD_RIGHTS_WRITE
  205. | POLICY_TRUST_ADMIN
  206. | POLICY_CREATE_ACCOUNT
  207. | POLICY_CREATE_SECRET
  208. | POLICY_CREATE_PRIVILEGE
  209. | POLICY_SET_DEFAULT_QUOTA_LIMITS
  210. | POLICY_SET_AUDIT_REQUIREMENTS
  211. | POLICY_AUDIT_LOG_ADMIN
  212. | POLICY_SERVER_ADMIN
  213. )
  214. POLICY_EXECUTE = (
  215. STANDARD_RIGHTS_EXECUTE
  216. | POLICY_VIEW_LOCAL_INFORMATION
  217. | POLICY_LOOKUP_NAMES
  218. )
  219. class TokenAccess:
  220. TOKEN_QUERY = 0x8
  221. class TokenInformationClass:
  222. TokenUser = 1
  223. class TOKEN_USER(ctypes.Structure):
  224. num = 1
  225. _fields_ = [
  226. ("SID", ctypes.c_void_p),
  227. ("ATTRIBUTES", ctypes.wintypes.DWORD),
  228. ]
  229. class SECURITY_DESCRIPTOR(ctypes.Structure):
  230. """
  231. typedef struct _SECURITY_DESCRIPTOR
  232. {
  233. UCHAR Revision;
  234. UCHAR Sbz1;
  235. SECURITY_DESCRIPTOR_CONTROL Control;
  236. PSID Owner;
  237. PSID Group;
  238. PACL Sacl;
  239. PACL Dacl;
  240. } SECURITY_DESCRIPTOR;
  241. """
  242. SECURITY_DESCRIPTOR_CONTROL = ctypes.wintypes.USHORT
  243. REVISION = 1
  244. _fields_ = [
  245. ("Revision", ctypes.c_ubyte),
  246. ("Sbz1", ctypes.c_ubyte),
  247. ("Control", SECURITY_DESCRIPTOR_CONTROL),
  248. ("Owner", ctypes.c_void_p),
  249. ("Group", ctypes.c_void_p),
  250. ("Sacl", ctypes.c_void_p),
  251. ("Dacl", ctypes.c_void_p),
  252. ]
  253. class SECURITY_ATTRIBUTES(ctypes.Structure):
  254. """
  255. typedef struct _SECURITY_ATTRIBUTES {
  256. DWORD nLength;
  257. LPVOID lpSecurityDescriptor;
  258. BOOL bInheritHandle;
  259. } SECURITY_ATTRIBUTES;
  260. """
  261. _fields_ = [
  262. ("nLength", ctypes.wintypes.DWORD),
  263. ("lpSecurityDescriptor", ctypes.c_void_p),
  264. ("bInheritHandle", ctypes.wintypes.BOOL),
  265. ]
  266. def __init__(self, *args, **kwargs):
  267. super(SECURITY_ATTRIBUTES, self).__init__(*args, **kwargs)
  268. self.nLength = ctypes.sizeof(SECURITY_ATTRIBUTES)
  269. @property
  270. def descriptor(self):
  271. return self._descriptor
  272. @descriptor.setter
  273. def descriptor(self, value):
  274. self._descriptor = value
  275. self.lpSecurityDescriptor = ctypes.addressof(value)
  276. ctypes.windll.advapi32.SetSecurityDescriptorOwner.argtypes = (
  277. ctypes.POINTER(SECURITY_DESCRIPTOR),
  278. ctypes.c_void_p,
  279. ctypes.wintypes.BOOL,
  280. )
  281. #########################
  282. # jaraco.windows.security
  283. def GetTokenInformation(token, information_class):
  284. """
  285. Given a token, get the token information for it.
  286. """
  287. data_size = ctypes.wintypes.DWORD()
  288. ctypes.windll.advapi32.GetTokenInformation(
  289. token, information_class.num, 0, 0, ctypes.byref(data_size)
  290. )
  291. data = ctypes.create_string_buffer(data_size.value)
  292. handle_nonzero_success(
  293. ctypes.windll.advapi32.GetTokenInformation(
  294. token,
  295. information_class.num,
  296. ctypes.byref(data),
  297. ctypes.sizeof(data),
  298. ctypes.byref(data_size),
  299. )
  300. )
  301. return ctypes.cast(data, ctypes.POINTER(TOKEN_USER)).contents
  302. def OpenProcessToken(proc_handle, access):
  303. result = ctypes.wintypes.HANDLE()
  304. proc_handle = ctypes.wintypes.HANDLE(proc_handle)
  305. handle_nonzero_success(
  306. ctypes.windll.advapi32.OpenProcessToken(
  307. proc_handle, access, ctypes.byref(result)
  308. )
  309. )
  310. return result
  311. def get_current_user():
  312. """
  313. Return a TOKEN_USER for the owner of this process.
  314. """
  315. process = OpenProcessToken(
  316. ctypes.windll.kernel32.GetCurrentProcess(), TokenAccess.TOKEN_QUERY
  317. )
  318. return GetTokenInformation(process, TOKEN_USER)
  319. def get_security_attributes_for_user(user=None):
  320. """
  321. Return a SECURITY_ATTRIBUTES structure with the SID set to the
  322. specified user (uses current user if none is specified).
  323. """
  324. if user is None:
  325. user = get_current_user()
  326. assert isinstance(user, TOKEN_USER), "user must be TOKEN_USER instance"
  327. SD = SECURITY_DESCRIPTOR()
  328. SA = SECURITY_ATTRIBUTES()
  329. # by attaching the actual security descriptor, it will be garbage-
  330. # collected with the security attributes
  331. SA.descriptor = SD
  332. SA.bInheritHandle = 1
  333. ctypes.windll.advapi32.InitializeSecurityDescriptor(
  334. ctypes.byref(SD), SECURITY_DESCRIPTOR.REVISION
  335. )
  336. ctypes.windll.advapi32.SetSecurityDescriptorOwner(
  337. ctypes.byref(SD), user.SID, 0
  338. )
  339. return SA