From 24dc69a9a97e82a6e4207de68d6dcc664178249b Mon Sep 17 00:00:00 2001 From: Seth Chisamore Date: Tue, 30 Oct 2012 10:39:35 -0400 Subject: [OC-3564] move core Chef to the repo root \o/ \m/ The opscode/chef repository now only contains the core Chef library code used by chef-client, knife and chef-solo! --- lib/chef/win32/api.rb | 364 ++++++++++ lib/chef/win32/api/error.rb | 921 +++++++++++++++++++++++++ lib/chef/win32/api/file.rb | 535 ++++++++++++++ lib/chef/win32/api/memory.rb | 105 +++ lib/chef/win32/api/process.rb | 40 ++ lib/chef/win32/api/psapi.rb | 51 ++ lib/chef/win32/api/security.rb | 341 +++++++++ lib/chef/win32/api/system.rb | 192 ++++++ lib/chef/win32/api/unicode.rb | 178 +++++ lib/chef/win32/error.rb | 73 ++ lib/chef/win32/file.rb | 167 +++++ lib/chef/win32/file/info.rb | 100 +++ lib/chef/win32/handle.rb | 48 ++ lib/chef/win32/memory.rb | 101 +++ lib/chef/win32/process.rb | 84 +++ lib/chef/win32/security.rb | 489 +++++++++++++ lib/chef/win32/security/ace.rb | 125 ++++ lib/chef/win32/security/acl.rb | 101 +++ lib/chef/win32/security/securable_object.rb | 109 +++ lib/chef/win32/security/security_descriptor.rb | 93 +++ lib/chef/win32/security/sid.rb | 199 ++++++ lib/chef/win32/security/token.rb | 64 ++ lib/chef/win32/unicode.rb | 43 ++ lib/chef/win32/version.rb | 119 ++++ 24 files changed, 4642 insertions(+) create mode 100644 lib/chef/win32/api.rb create mode 100644 lib/chef/win32/api/error.rb create mode 100644 lib/chef/win32/api/file.rb create mode 100644 lib/chef/win32/api/memory.rb create mode 100644 lib/chef/win32/api/process.rb create mode 100644 lib/chef/win32/api/psapi.rb create mode 100644 lib/chef/win32/api/security.rb create mode 100644 lib/chef/win32/api/system.rb create mode 100644 lib/chef/win32/api/unicode.rb create mode 100644 lib/chef/win32/error.rb create mode 100644 lib/chef/win32/file.rb create mode 100644 lib/chef/win32/file/info.rb create mode 100644 lib/chef/win32/handle.rb create mode 100644 lib/chef/win32/memory.rb create mode 100644 lib/chef/win32/process.rb create mode 100644 lib/chef/win32/security.rb create mode 100644 lib/chef/win32/security/ace.rb create mode 100644 lib/chef/win32/security/acl.rb create mode 100644 lib/chef/win32/security/securable_object.rb create mode 100644 lib/chef/win32/security/security_descriptor.rb create mode 100644 lib/chef/win32/security/sid.rb create mode 100644 lib/chef/win32/security/token.rb create mode 100644 lib/chef/win32/unicode.rb create mode 100644 lib/chef/win32/version.rb (limited to 'lib/chef/win32') diff --git a/lib/chef/win32/api.rb b/lib/chef/win32/api.rb new file mode 100644 index 0000000000..0330810b3b --- /dev/null +++ b/lib/chef/win32/api.rb @@ -0,0 +1,364 @@ +# +# Author:: Seth Chisamore () +# Author:: John Keiser () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'ffi' +require 'chef/reserved_names' +require 'chef/exceptions' + +class Chef + module ReservedNames::Win32 + module API + + # Attempts to use FFI's attach_function method to link a native Win32 + # function into the calling module. If this fails a dummy method is + # defined which when called, raises a helpful exception to the end-user. + def safe_attach_function(win32_func, *args) + begin + attach_function(win32_func.to_sym, *args) + rescue FFI::NotFoundError + define_method(win32_func.to_sym) do |*margs| + raise Chef::Exceptions::Win32APIFunctionNotImplemented, "This version of Windows does not implement the Win32 function [#{win32_func}]." + end + end + end + + # put shared stuff (like constants) for all raw Win32 API calls + def self.extended(host) + host.extend FFI::Library + host.extend Macros + + host.ffi_convention :stdcall + + # Windows-specific type defs (ms-help://MS.MSDNQTR.v90.en/winprog/winprog/windows_data_types.htm): + host.typedef :ushort, :ATOM # Atom ~= Symbol: Atom table stores strings and corresponding identifiers. Application + # places a string in an atom table and receives a 16-bit integer, called an atom, that + # can be used to access the string. Placed string is called an atom name. + # See: http://msdn.microsoft.com/en-us/library/ms648708%28VS.85%29.aspx + host.typedef :bool, :BOOL + host.typedef :bool, :BOOLEAN + host.typedef :uchar, :BYTE # Byte (8 bits). Declared as unsigned char + #CALLBACK: K, # Win32.API gem-specific ?? MSDN: #define CALLBACK __stdcall + host.typedef :char, :CHAR # 8-bit Windows (ANSI) character. See http://msdn.microsoft.com/en-us/library/dd183415%28VS.85%29.aspx + host.typedef :uint32, :COLORREF # Red, green, blue (RGB) color value (32 bits). See COLORREF for more info. + host.typedef :uint32, :DWORD # 32-bit unsigned integer. The range is 0 through 4,294,967,295 decimal. + host.typedef :uint64, :DWORDLONG # 64-bit unsigned integer. The range is 0 through 18,446,744,073,709,551,615 decimal. + host.typedef :ulong, :DWORD_PTR # Unsigned long type for pointer precision. Use when casting a pointer to a long type + # to perform pointer arithmetic. (Also commonly used for general 32-bit parameters that have + # been extended to 64 bits in 64-bit Windows.) BaseTsd.h: #host.typedef ULONG_PTR DWORD_PTR; + host.typedef :uint32, :DWORD32 + host.typedef :uint64, :DWORD64 + host.typedef :int, :HALF_PTR # Half the size of a pointer. Use within a structure that contains a pointer and two small fields. + # BaseTsd.h: #ifdef (_WIN64) host.typedef int HALF_PTR; #else host.typedef short HALF_PTR; + host.typedef :ulong, :HACCEL # (L) Handle to an accelerator table. WinDef.h: #host.typedef HANDLE HACCEL; + # See http://msdn.microsoft.com/en-us/library/ms645526%28VS.85%29.aspx + host.typedef :ulong, :HANDLE # (L) Handle to an object. WinNT.h: #host.typedef PVOID HANDLE; + # todo: Platform-dependent! Need to change to :uint64 for Win64 + host.typedef :ulong, :HBITMAP # (L) Handle to a bitmap: http://msdn.microsoft.com/en-us/library/dd183377%28VS.85%29.aspx + host.typedef :ulong, :HBRUSH # (L) Handle to a brush. http://msdn.microsoft.com/en-us/library/dd183394%28VS.85%29.aspx + host.typedef :ulong, :HCOLORSPACE # (L) Handle to a color space. http://msdn.microsoft.com/en-us/library/ms536546%28VS.85%29.aspx + host.typedef :ulong, :HCURSOR # (L) Handle to a cursor. http://msdn.microsoft.com/en-us/library/ms646970%28VS.85%29.aspx + host.typedef :ulong, :HCONV # (L) Handle to a dynamic data exchange (DDE) conversation. + host.typedef :ulong, :HCONVLIST # (L) Handle to a DDE conversation list. HANDLE - L ? + host.typedef :ulong, :HDDEDATA # (L) Handle to DDE data (structure?) + host.typedef :ulong, :HDC # (L) Handle to a device context (DC). http://msdn.microsoft.com/en-us/library/dd183560%28VS.85%29.aspx + host.typedef :ulong, :HDESK # (L) Handle to a desktop. http://msdn.microsoft.com/en-us/library/ms682573%28VS.85%29.aspx + host.typedef :ulong, :HDROP # (L) Handle to an internal drop structure. + host.typedef :ulong, :HDWP # (L) Handle to a deferred window position structure. + host.typedef :ulong, :HENHMETAFILE #(L) Handle to an enhanced metafile. http://msdn.microsoft.com/en-us/library/dd145051%28VS.85%29.aspx + host.typedef :uint, :HFILE # (I) Special file handle to a file opened by OpenFile, not CreateFile. + # WinDef.h: #host.typedef int HFILE; + host.typedef :ulong, :HFONT # (L) Handle to a font. http://msdn.microsoft.com/en-us/library/dd162470%28VS.85%29.aspx + host.typedef :ulong, :HGDIOBJ # (L) Handle to a GDI object. + host.typedef :ulong, :HGLOBAL # (L) Handle to a global memory block. + host.typedef :ulong, :HHOOK # (L) Handle to a hook. http://msdn.microsoft.com/en-us/library/ms632589%28VS.85%29.aspx + host.typedef :ulong, :HICON # (L) Handle to an icon. http://msdn.microsoft.com/en-us/library/ms646973%28VS.85%29.aspx + host.typedef :ulong, :HINSTANCE # (L) Handle to an instance. This is the base address of the module in memory. + # HMODULE and HINSTANCE are the same today, but were different in 16-bit Windows. + host.typedef :ulong, :HKEY # (L) Handle to a registry key. + host.typedef :ulong, :HKL # (L) Input locale identifier. + host.typedef :ulong, :HLOCAL # (L) Handle to a local memory block. + host.typedef :ulong, :HMENU # (L) Handle to a menu. http://msdn.microsoft.com/en-us/library/ms646977%28VS.85%29.aspx + host.typedef :ulong, :HMETAFILE # (L) Handle to a metafile. http://msdn.microsoft.com/en-us/library/dd145051%28VS.85%29.aspx + host.typedef :ulong, :HMODULE # (L) Handle to an instance. Same as HINSTANCE today, but was different in 16-bit Windows. + host.typedef :ulong, :HMONITOR # (L) Рandle to a display monitor. WinDef.h: if(WINVER >= 0x0500) host.typedef HANDLE HMONITOR; + host.typedef :ulong, :HPALETTE # (L) Handle to a palette. + host.typedef :ulong, :HPEN # (L) Handle to a pen. http://msdn.microsoft.com/en-us/library/dd162786%28VS.85%29.aspx + host.typedef :long, :HRESULT # Return code used by COM interfaces. For more info, Structure of the COM Error Codes. + # To test an HRESULT value, use the FAILED and SUCCEEDED macros. + host.typedef :ulong, :HRGN # (L) Handle to a region. http://msdn.microsoft.com/en-us/library/dd162913%28VS.85%29.aspx + host.typedef :ulong, :HRSRC # (L) Handle to a resource. + host.typedef :ulong, :HSZ # (L) Handle to a DDE string. + host.typedef :ulong, :HWINSTA # (L) Handle to a window station. http://msdn.microsoft.com/en-us/library/ms687096%28VS.85%29.aspx + host.typedef :ulong, :HWND # (L) Handle to a window. http://msdn.microsoft.com/en-us/library/ms632595%28VS.85%29.aspx + host.typedef :int, :INT # 32-bit signed integer. The range is -2147483648 through 2147483647 decimal. + host.typedef :int, :INT_PTR # Signed integer type for pointer precision. Use when casting a pointer to an integer + # to perform pointer arithmetic. BaseTsd.h: + #if defined(_WIN64) host.typedef __int64 INT_PTR; #else host.typedef int INT_PTR; + host.typedef :int32, :INT32 # 32-bit signed integer. The range is -2,147,483,648 through +...647 decimal. + host.typedef :int64, :INT64 # 64-bit signed integer. The range is –9,223,372,036,854,775,808 through +...807 + host.typedef :ushort, :LANGID # Language identifier. For more information, see Locales. WinNT.h: #host.typedef WORD LANGID; + # See http://msdn.microsoft.com/en-us/library/dd318716%28VS.85%29.aspx + host.typedef :uint32, :LCID # Locale identifier. For more information, see Locales. + host.typedef :uint32, :LCTYPE # Locale information type. For a list, see Locale Information Constants. + host.typedef :uint32, :LGRPID # Language group identifier. For a list, see EnumLanguageGroupLocales. + host.typedef :long, :LONG # 32-bit signed integer. The range is -2,147,483,648 through +...647 decimal. + host.typedef :int32, :LONG32 # 32-bit signed integer. The range is -2,147,483,648 through +...647 decimal. + host.typedef :int64, :LONG64 # 64-bit signed integer. The range is –9,223,372,036,854,775,808 through +...807 + host.typedef :int64, :LONGLONG # 64-bit signed integer. The range is –9,223,372,036,854,775,808 through +...807 + host.typedef :long, :LONG_PTR # Signed long type for pointer precision. Use when casting a pointer to a long to + # perform pointer arithmetic. BaseTsd.h: + #if defined(_WIN64) host.typedef __int64 LONG_PTR; #else host.typedef long LONG_PTR; + host.typedef :long, :LPARAM # Message parameter. WinDef.h as follows: #host.typedef LONG_PTR LPARAM; + host.typedef :pointer, :LPBOOL # Pointer to a BOOL. WinDef.h as follows: #host.typedef BOOL far *LPBOOL; + host.typedef :pointer, :LPBYTE # Pointer to a BYTE. WinDef.h as follows: #host.typedef BYTE far *LPBYTE; + host.typedef :pointer, :LPCOLORREF # Pointer to a COLORREF value. WinDef.h as follows: #host.typedef DWORD *LPCOLORREF; + host.typedef :pointer, :LPCSTR # Pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters. + # See Character Sets Used By Fonts. http://msdn.microsoft.com/en-us/library/dd183415%28VS.85%29.aspx + host.typedef :pointer, :LPCTSTR # An LPCWSTR if UNICODE is defined, an LPCSTR otherwise. + host.typedef :pointer, :LPCVOID # Pointer to a constant of any type. WinDef.h as follows: host.typedef CONST void *LPCVOID; + host.typedef :pointer, :LPCWSTR # Pointer to a constant null-terminated string of 16-bit Unicode characters. + host.typedef :pointer, :LPDWORD # Pointer to a DWORD. WinDef.h as follows: host.typedef DWORD *LPDWORD; + host.typedef :pointer, :LPHANDLE # Pointer to a HANDLE. WinDef.h as follows: host.typedef HANDLE *LPHANDLE; + host.typedef :pointer, :LPINT # Pointer to an INT. + host.typedef :pointer, :LPLONG # Pointer to an LONG. + host.typedef :pointer, :LPSECURITY_ATTRIBUTES # Pointer to SECURITY_ATTRIBUTES struct + host.typedef :pointer, :LPSTR # Pointer to a null-terminated string of 8-bit Windows (ANSI) characters. + host.typedef :pointer, :LPTSTR # An LPWSTR if UNICODE is defined, an LPSTR otherwise. + host.typedef :pointer, :LPVOID # Pointer to any type. + host.typedef :pointer, :LPWORD # Pointer to a WORD. + host.typedef :pointer, :LPWSTR # Pointer to a null-terminated string of 16-bit Unicode characters. + host.typedef :long, :LRESULT # Signed result of message processing. WinDef.h: host.typedef LONG_PTR LRESULT; + host.typedef :pointer, :LPWIN32_FIND_DATA # Pointer to WIN32_FIND_DATA struct + host.typedef :pointer, :LPBY_HANDLE_FILE_INFORMATION # Point to a BY_HANDLE_FILE_INFORMATION struct + host.typedef :pointer, :PBOOL # Pointer to a BOOL. + host.typedef :pointer, :PBOOLEAN # Pointer to a BOOL. + host.typedef :pointer, :PBYTE # Pointer to a BYTE. + host.typedef :pointer, :PCHAR # Pointer to a CHAR. + host.typedef :pointer, :PCSTR # Pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters. + host.typedef :pointer, :PCTSTR # A PCWSTR if UNICODE is defined, a PCSTR otherwise. + host.typedef :pointer, :PCWSTR # Pointer to a constant null-terminated string of 16-bit Unicode characters. + host.typedef :pointer, :PDWORD # Pointer to a DWORD. + host.typedef :pointer, :PDWORDLONG # Pointer to a DWORDLONG. + host.typedef :pointer, :PDWORD_PTR # Pointer to a DWORD_PTR. + host.typedef :pointer, :PDWORD32 # Pointer to a DWORD32. + host.typedef :pointer, :PDWORD64 # Pointer to a DWORD64. + host.typedef :pointer, :PFLOAT # Pointer to a FLOAT. + host.typedef :pointer, :PHALF_PTR # Pointer to a HALF_PTR. + host.typedef :pointer, :PHANDLE # Pointer to a HANDLE. + host.typedef :pointer, :PHKEY # Pointer to an HKEY. + host.typedef :pointer, :PINT # Pointer to an INT. + host.typedef :pointer, :PINT_PTR # Pointer to an INT_PTR. + host.typedef :pointer, :PINT32 # Pointer to an INT32. + host.typedef :pointer, :PINT64 # Pointer to an INT64. + host.typedef :pointer, :PLCID # Pointer to an LCID. + host.typedef :pointer, :PLONG # Pointer to a LONG. + host.typedef :pointer, :PLONGLONG # Pointer to a LONGLONG. + host.typedef :pointer, :PLONG_PTR # Pointer to a LONG_PTR. + host.typedef :pointer, :PLONG32 # Pointer to a LONG32. + host.typedef :pointer, :PLONG64 # Pointer to a LONG64. + host.typedef :pointer, :PLUID # Pointer to a LUID. + host.typedef :pointer, :POINTER_32 # 32-bit pointer. On a 32-bit system, this is a native pointer. On a 64-bit system, this is a truncated 64-bit pointer. + host.typedef :pointer, :POINTER_64 # 64-bit pointer. On a 64-bit system, this is a native pointer. On a 32-bit system, this is a sign-extended 32-bit pointer. + host.typedef :pointer, :POINTER_SIGNED # A signed pointer. + host.typedef :pointer, :POINTER_UNSIGNED # An unsigned pointer. + host.typedef :pointer, :PSHORT # Pointer to a SHORT. + host.typedef :pointer, :PSIZE_T # Pointer to a SIZE_T. + host.typedef :pointer, :PSSIZE_T # Pointer to a SSIZE_T. + host.typedef :pointer, :PSTR # Pointer to a null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts. + host.typedef :pointer, :PTBYTE # Pointer to a TBYTE. + host.typedef :pointer, :PTCHAR # Pointer to a TCHAR. + host.typedef :pointer, :PTSTR # A PWSTR if UNICODE is defined, a PSTR otherwise. + host.typedef :pointer, :PUCHAR # Pointer to a UCHAR. + host.typedef :pointer, :PUHALF_PTR # Pointer to a UHALF_PTR. + host.typedef :pointer, :PUINT # Pointer to a UINT. + host.typedef :pointer, :PUINT_PTR # Pointer to a UINT_PTR. + host.typedef :pointer, :PUINT32 # Pointer to a UINT32. + host.typedef :pointer, :PUINT64 # Pointer to a UINT64. + host.typedef :pointer, :PULONG # Pointer to a ULONG. + host.typedef :pointer, :PULONGLONG # Pointer to a ULONGLONG. + host.typedef :pointer, :PULONG_PTR # Pointer to a ULONG_PTR. + host.typedef :pointer, :PULONG32 # Pointer to a ULONG32. + host.typedef :pointer, :PULONG64 # Pointer to a ULONG64. + host.typedef :pointer, :PUSHORT # Pointer to a USHORT. + host.typedef :pointer, :PVOID # Pointer to any type. + host.typedef :pointer, :PWCHAR # Pointer to a WCHAR. + host.typedef :pointer, :PWORD # Pointer to a WORD. + host.typedef :pointer, :PWSTR # Pointer to a null- terminated string of 16-bit Unicode characters. + # For more information, see Character Sets Used By Fonts. + host.typedef :ulong, :SC_HANDLE # (L) Handle to a service control manager database. + # See SCM Handles http://msdn.microsoft.com/en-us/library/ms685104%28VS.85%29.aspx + host.typedef :pointer, :SC_LOCK # Lock to a service control manager database. For more information, see SCM Handles. + host.typedef :ulong, :SERVICE_STATUS_HANDLE # (L) Handle to a service status value. See SCM Handles. + host.typedef :short, :SHORT # A 16-bit integer. The range is –32768 through 32767 decimal. + host.typedef :ulong, :SIZE_T # The maximum number of bytes to which a pointer can point. Use for a count that must span the full range of a pointer. + host.typedef :long, :SSIZE_T # Signed SIZE_T. + host.typedef :char, :TBYTE # A WCHAR if UNICODE is defined, a CHAR otherwise.TCHAR: + # http://msdn.microsoft.com/en-us/library/c426s321%28VS.80%29.aspx + host.typedef :char, :TCHAR # A WCHAR if UNICODE is defined, a CHAR otherwise.TCHAR: + host.typedef :uchar, :UCHAR # Unsigned CHAR (8 bit) + host.typedef :uint, :UHALF_PTR # Unsigned HALF_PTR. Use within a structure that contains a pointer and two small fields. + host.typedef :uint, :UINT # Unsigned INT. The range is 0 through 4294967295 decimal. + host.typedef :uint, :UINT_PTR # Unsigned INT_PTR. + host.typedef :uint32, :UINT32 # Unsigned INT32. The range is 0 through 4294967295 decimal. + host.typedef :uint64, :UINT64 # Unsigned INT64. The range is 0 through 18446744073709551615 decimal. + host.typedef :ulong, :ULONG # Unsigned LONG. The range is 0 through 4294967295 decimal. + host.typedef :ulong_long, :ULONGLONG # 64-bit unsigned integer. The range is 0 through 18446744073709551615 decimal. + host.typedef :ulong, :ULONG_PTR # Unsigned LONG_PTR. + host.typedef :uint32, :ULONG32 # Unsigned INT32. The range is 0 through 4294967295 decimal. + host.typedef :uint64, :ULONG64 # Unsigned LONG64. The range is 0 through 18446744073709551615 decimal. + host.typedef :pointer, :UNICODE_STRING # Pointer to some string structure?? + host.typedef :ushort, :USHORT # Unsigned SHORT. The range is 0 through 65535 decimal. + host.typedef :ulong_long, :USN # Update sequence number (USN). + host.typedef :ushort, :WCHAR # 16-bit Unicode character. For more information, see Character Sets Used By Fonts. + # In WinNT.h: host.typedef wchar_t WCHAR; + #WINAPI: K, # Calling convention for system functions. WinDef.h: define WINAPI __stdcall + host.typedef :ushort, :WORD # 16-bit unsigned integer. The range is 0 through 65535 decimal. + host.typedef :uint, :WPARAM # Message parameter. WinDef.h as follows: host.typedef UINT_PTR WPARAM; + end + + module Macros + + ############################################### + # winbase.h + ############################################### + + def LocalDiscard(pointer) + LocalReAlloc(pointer, 0, LMEM_MOVEABLE) + end + + ############################################### + # windef.h + ############################################### + + # Creates a WORD value by concatenating the specified values. + # + # http://msdn.microsoft.com/en-us/library/windows/desktop/ms632663(v=VS.85).aspx + def MAKEWORD(low, high) + ((low & 0xff) | (high & 0xff)) << 8 + end + + # Creates a LONG value by concatenating the specified values. + # + # http://msdn.microsoft.com/en-us/library/windows/desktop/ms632660(v=vs.85).aspx + def MAKELONG(low, high) + ((low & 0xffff) | (high & 0xffff)) << 16 + end + + # Retrieves the low-order word from the specified value. + # + # http://msdn.microsoft.com/en-us/library/windows/desktop/ms632659(v=VS.85).aspx + def LOWORD(l) + l & 0xffff + end + + # Retrieves the high-order word from the specified 32-bit value. + # + # http://msdn.microsoft.com/en-us/library/windows/desktop/ms632657(v=VS.85).aspx + def HIWORD(l) + l >> 16 + end + + # Retrieves the low-order byte from the specified value. + # + # http://msdn.microsoft.com/en-us/library/windows/desktop/ms632658(v=VS.85).aspx + def LOBYTE(w) + w & 0xff + end + + # Retrieves the high-order byte from the given 16-bit value. + # + # http://msdn.microsoft.com/en-us/library/windows/desktop/ms632656(v=VS.85).aspx + def HIBYTE(w) + w >> 8 + end + + ############################################### + # winerror.h + ############################################### + + def IS_ERROR(status) + status >> 31 == 1 + end + + def MAKE_HRESULT(sev, fac, code) + sev << 31 | fac << 16 | code + end + + def MAKE_SCODE(sev, fac, code) + sev << 31 | fac << 16 | code + end + + def HRESULT_CODE(hr) + hr & 0xFFFF + end + + def HRESULT_FACILITY(hr) + (hr >> 16) & 0x1fff + end + + def HRESULT_FROM_NT(x) + x | 0x10000000 # FACILITY_NT_BIT + end + + def HRESULT_FROM_WIN32(x) + if x <= 0 + x + else + (x & 0x0000FFFF) | (7 << 16) | 0x80000000 + end + end + + def HRESULT_SEVERITY(hr) + (hr >> 31) & 0x1 + end + + def FAILED(status) + status < 0 + end + + def SUCCEEDED(status) + status >= 0 + end + end + + # Represents a 64-bit unsigned integer value. + # + # http://msdn.microsoft.com/en-us/library/windows/desktop/aa383742(v=vs.85).aspx + def make_uint64(low, high) + low + (high * (2**32)) + end + + # http://blogs.msdn.com/b/oldnewthing/archive/2009/03/06/9461176.aspx + # January 1, 1601 + WIN32_EPOC_MINUS_POSIX_EPOC = 116444736000000000 + + # Convert 64-bit FILETIME integer into Time object. + # + # FILETIME structure contains a 64-bit value representing the number + # of 100-nanosecond intervals since January 1, 1601 (UTC). + # + # http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx + # + def wtime_to_time(wtime) + Time.at((wtime - WIN32_EPOC_MINUS_POSIX_EPOC) / 10000000) + end + + end + end +end diff --git a/lib/chef/win32/api/error.rb b/lib/chef/win32/api/error.rb new file mode 100644 index 0000000000..d1f9a309fe --- /dev/null +++ b/lib/chef/win32/api/error.rb @@ -0,0 +1,921 @@ +# +# Author:: John Keiser () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/api' + +class Chef + module ReservedNames::Win32 + module API + module Error + extend Chef::ReservedNames::Win32::API + + ############################################### + # Win32 API Constants + ############################################### + + S_OK = 0 + NO_ERROR = 0 + ERROR_SUCCESS = 0 + ERROR_INVALID_FUNCTION = 1 + ERROR_FILE_NOT_FOUND = 2 + ERROR_PATH_NOT_FOUND = 3 + ERROR_TOO_MANY_OPEN_FILES = 4 + ERROR_ACCESS_DENIED = 5 + ERROR_INVALID_HANDLE = 6 + ERROR_ARENA_TRASHED = 7 + ERROR_NOT_ENOUGH_MEMORY = 8 + ERROR_INVALID_BLOCK = 9 + ERROR_BAD_ENVIRONMENT = 10 + ERROR_BAD_FORMAT = 11 + ERROR_INVALID_ACCESS = 12 + ERROR_INVALID_DATA = 13 + ERROR_INVALID_DRIVE = 15 + ERROR_CURRENT_DIRECTORY = 16 + ERROR_NOT_SAME_DEVICE = 17 + ERROR_NO_MORE_FILES = 18 + ERROR_WRITE_PROTECT = 19 + ERROR_BAD_UNIT = 20 + ERROR_NOT_READY = 21 + ERROR_BAD_COMMAND = 22 + ERROR_CRC = 23 + ERROR_BAD_LENGTH = 24 + ERROR_SEEK = 25 + ERROR_NOT_DOS_DISK = 26 + ERROR_SECTOR_NOT_FOUND = 27 + ERROR_OUT_OF_PAPER = 28 + ERROR_WRITE_FAULT = 29 + ERROR_READ_FAULT = 30 + ERROR_GEN_FAILURE = 31 + ERROR_SHARING_VIOLATION = 32 + ERROR_LOCK_VIOLATION = 33 + ERROR_WRONG_DISK = 34 + ERROR_FCB_UNAVAILABLE = 35 # gets returned for some unsuccessful DeviceIoControl calls + ERROR_SHARING_BUFFER_EXCEEDED = 36 + ERROR_HANDLE_EOF = 38 + ERROR_HANDLE_DISK_FULL = 39 + + ERROR_NOT_SUPPORTED = 50 + ERROR_REM_NOT_LIST = 51 + ERROR_DUP_NAME = 52 + ERROR_BAD_NETPATH = 53 + ERROR_NETWORK_BUSY = 54 + ERROR_DEV_NOT_EXIST = 55 + ERROR_TOO_MANY_CMDS = 56 + ERROR_ADAP_HDW_ERR = 57 + ERROR_BAD_NET_RESP = 58 + ERROR_UNEXP_NET_ERR = 59 + ERROR_BAD_REM_ADAP = 60 + ERROR_PRINTQ_FULL = 61 + ERROR_NO_SPOOL_SPACE = 62 + ERROR_PRINT_CANCELLED = 63 + ERROR_NETNAME_DELETED = 64 + ERROR_NETWORK_ACCESS_DENIED = 65 + ERROR_BAD_DEV_TYPE = 66 + ERROR_BAD_NET_NAME = 67 + ERROR_TOO_MANY_NAMES = 68 + ERROR_TOO_MANY_SESS = 69 + ERROR_SHARING_PAUSED = 70 + ERROR_REQ_NOT_ACCEP = 71 + ERROR_REDIR_PAUSED = 72 + + ERROR_FILE_EXISTS = 80 + ERROR_DUP_FCB = 81 + ERROR_CANNOT_MAKE = 82 + ERROR_FAIL_I24 = 83 + ERROR_OUT_OF_STRUCTURES = 84 + ERROR_ALREADY_ASSIGNED = 85 + ERROR_INVALID_PASSWORD = 86 + ERROR_INVALID_PARAMETER = 87 + ERROR_NET_WRITE_FAULT = 88 + ERROR_NO_PROC_SLOTS = 89 # no process slots available + ERROR_NOT_FROZEN = 90 + ERR_TSTOVFL = 91 # timer service table overflow + ERR_TSTDUP = 92 # timer service table duplicate + ERROR_NO_ITEMS = 93 # There were no items to operate upon + ERROR_INTERRUPT = 95 # interrupted system call + + ERROR_TOO_MANY_SEMAPHORES = 100 + ERROR_EXCL_SEM_ALREADY_OWNED = 101 + ERROR_SEM_IS_SET = 102 + ERROR_TOO_MANY_SEM_REQUESTS = 103 + ERROR_INVALID_AT_INTERRUPT_TIME = 104 + ERROR_SEM_OWNER_DIED = 105 # waitsem found owner died + ERROR_SEM_USER_LIMIT = 106 # too many procs have this sem + ERROR_DISK_CHANGE = 107 # insert disk b into drive a + ERROR_DRIVE_LOCKED = 108 # drive locked by another process + ERROR_BROKEN_PIPE = 109 # write on pipe with no reader + ERROR_OPEN_FAILED = 110 # open/created failed + ERROR_DISK_FULL = 112 # not enough space + ERROR_NO_MORE_SEARCH_HANDLES = 113 # can't allocate + ERROR_INVALID_TARGET_HANDLE = 114 # handle in DOSDUPHANDLE is invalid + ERROR_PROTECTION_VIOLATION = 115 # bad user virtual address + ERROR_VIOKBD_REQUEST = 116 + ERROR_INVALID_CATEGORY = 117 # category for DEVIOCTL not defined + ERROR_INVALID_VERIFY_SWITCH = 118 # invalid value + ERROR_BAD_DRIVER_LEVEL = 119 # DosDevIOCTL not level four + ERROR_CALL_NOT_IMPLEMENTED = 120 + ERROR_SEM_TIMEOUT = 121 # timeout from semaphore function + ERROR_INSUFFICIENT_BUFFER = 122 + ERROR_INVALID_NAME = 123 # illegal char or malformed file system name + ERROR_INVALID_LEVEL = 124 # unimplemented level for info retrieval + ERROR_NO_VOLUME_LABEL = 125 # no volume label found + ERROR_MOD_NOT_FOUND = 126 # w_getprocaddr, w_getmodhandle + ERROR_PROC_NOT_FOUND = 127 # w_getprocaddr + ERROR_WAIT_NO_CHILDREN = 128 # CWait finds to children + ERROR_CHILD_NOT_COMPLETE = 129 # CWait children not dead yet + ERROR_DIRECT_ACCESS_HANDLE = 130 # invalid for direct disk access + ERROR_NEGATIVE_SEEK = 131 # tried to seek negative offset + ERROR_SEEK_ON_DEVICE = 132 # tried to seek on device or pipe + ERROR_IS_JOIN_TARGET = 133 + ERROR_IS_JOINED = 134 + ERROR_IS_SUBSTED = 135 + ERROR_NOT_JOINED = 136 + ERROR_NOT_SUBSTED = 137 + ERROR_JOIN_TO_JOIN = 138 + ERROR_SUBST_TO_SUBST = 139 + ERROR_JOIN_TO_SUBST = 140 + ERROR_SUBST_TO_JOIN = 141 + ERROR_BUSY_DRIVE = 142 + ERROR_SAME_DRIVE = 143 + ERROR_DIR_NOT_ROOT = 144 + ERROR_DIR_NOT_EMPTY = 145 + ERROR_IS_SUBST_PATH = 146 + ERROR_IS_JOIN_PATH = 147 + ERROR_PATH_BUSY = 148 + ERROR_IS_SUBST_TARGET = 149 + ERROR_SYSTEM_TRACE = 150 # system trace error + ERROR_INVALID_EVENT_COUNT = 151 # DosMuxSemWait errors + ERROR_TOO_MANY_MUXWAITERS = 152 + ERROR_INVALID_LIST_FORMAT = 153 + ERROR_LABEL_TOO_LONG = 154 + ERROR_TOO_MANY_TCBS = 155 + ERROR_SIGNAL_REFUSED = 156 + ERROR_DISCARDED = 157 + ERROR_NOT_LOCKED = 158 + ERROR_BAD_THREADID_ADDR = 159 + ERROR_BAD_ARGUMENTS = 160 + ERROR_BAD_PATHNAME = 161 + ERROR_SIGNAL_PENDING = 162 + ERROR_UNCERTAIN_MEDIA = 163 + ERROR_MAX_THRDS_REACHED = 164 + ERROR_MONITORS_NOT_SUPPORTED = 165 + + ERROR_LOCK_FAILED = 167 + ERROR_BUSY = 170 + ERROR_CANCEL_VIOLATION = 173 + ERROR_ATOMIC_LOCKS_NOT_SUPPORTED= 174 + + ERROR_INVALID_SEGMENT_NUMBER = 180 + ERROR_INVALID_CALLGATE = 181 + ERROR_INVALID_ORDINAL = 182 + ERROR_ALREADY_EXISTS = 183 + ERROR_NO_CHILD_PROCESS = 184 + ERROR_CHILD_ALIVE_NOWAIT = 185 + ERROR_INVALID_FLAG_NUMBER = 186 + ERROR_SEM_NOT_FOUND = 187 + ERROR_INVALID_STARTING_CODESEG = 188 + ERROR_INVALID_STACKSEG = 189 + ERROR_INVALID_MODULETYPE = 190 + ERROR_INVALID_EXE_SIGNATURE = 191 + ERROR_EXE_MARKED_INVALID = 192 + ERROR_BAD_EXE_FORMAT = 193 + ERROR_ITERATED_DATA_EXCEEDS_64k = 194 + ERROR_INVALID_MINALLOCSIZE = 195 + ERROR_DYNLINK_FROM_INVALID_RING = 196 + ERROR_IOPL_NOT_ENABLED = 197 + ERROR_INVALID_SEGDPL = 198 + ERROR_AUTODATASEG_EXCEEDS_64k = 199 + ERROR_RING2SEG_MUST_BE_MOVABLE = 200 + ERROR_RELOC_CHAIN_XEEDS_SEGLIM = 201 + ERROR_INFLOOP_IN_RELOC_CHAIN = 202 + ERROR_ENVVAR_NOT_FOUND = 203 + ERROR_NOT_CURRENT_CTRY = 204 + ERROR_NO_SIGNAL_SENT = 205 + ERROR_FILENAME_EXCED_RANGE = 206 # if filename > 8.3 + ERROR_RING2_STACK_IN_USE = 207 # for FAPI + ERROR_META_EXPANSION_TOO_LONG = 208 # if "*a" > 8.3 + ERROR_INVALID_SIGNAL_NUMBER = 209 + ERROR_THREAD_1_INACTIVE = 210 + ERROR_INFO_NOT_AVAIL = 211 #@@ PTM 5550 + ERROR_LOCKED = 212 + ERROR_BAD_DYNALINK = 213 #@@ PTM 5760 + ERROR_TOO_MANY_MODULES = 214 + ERROR_NESTING_NOT_ALLOWED = 215 + ERROR_EXE_MACHINE_TYPE_MISMATCH = 216 + + ERROR_BAD_PIPE = 230 + ERROR_PIPE_BUSY = 231 + ERROR_NO_DATA = 232 + ERROR_PIPE_NOT_CONNECTED = 233 + ERROR_MORE_DATA = 234 + + ERROR_VC_DISCONNECTED = 240 + ERROR_INVALID_EA_NAME = 254 + ERROR_EA_LIST_INCONSISTENT = 255 + ERROR_NO_MORE_ITEMS = 259 + ERROR_CANNOT_COPY = 266 + ERROR_DIRECTORY = 267 + ERROR_EAS_DIDNT_FIT = 275 + ERROR_EA_FILE_CORRUPT = 276 + ERROR_EA_TABLE_FULL = 277 + ERROR_INVALID_EA_HANDLE = 278 + ERROR_EAS_NOT_SUPPORTED = 282 + ERROR_NOT_OWNER = 288 + ERROR_TOO_MANY_POSTS = 298 + ERROR_PARTIAL_COPY = 299 + ERROR_OPLOCK_NOT_GRANTED = 300 + ERROR_INVALID_OPLOCK_PROTOCOL = 301 + ERROR_DISK_TOO_FRAGMENTED = 302 + ERROR_MR_MID_NOT_FOUND = 317 + ERROR_SCOPE_NOT_FOUND = 318 + ERROR_FAIL_NOACTION_REBOOT = 350 + ERROR_FAIL_SHUTDOWN = 351 + ERROR_FAIL_RESTART = 352 + ERROR_MAX_SESSIONS_REACHED = 353 + ERROR_INVALID_ADDRESS = 487 + ERROR_USER_PROFILE_LOAD = 500 + ERROR_ARITHMETIC_OVERFLOW = 534 + ERROR_PIPE_CONNECTED = 535 + ERROR_PIPE_LISTENING = 536 + + ERROR_EA_ACCESS_DENIED = 994 + ERROR_OPERATION_ABORTED = 995 + ERROR_IO_INCOMPLETE = 996 + ERROR_IO_PENDING = 997 + ERROR_NOACCESS = 998 + ERROR_SWAPERROR = 999 + + ERROR_STACK_OVERFLOW = 1001 + ERROR_INVALID_MESSAGE = 1002 + ERROR_CAN_NOT_COMPLETE = 1003 + ERROR_INVALID_FLAGS = 1004 + ERROR_UNRECOGNIZED_VOLUME = 1005 + ERROR_FILE_INVALID = 1006 + ERROR_FULLSCREEN_MODE = 1007 + ERROR_NO_TOKEN = 1008 + ERROR_BADDB = 1009 + ERROR_BADKEY = 1010 + ERROR_CANTOPEN = 1011 + ERROR_CANTREAD = 1012 + ERROR_CANTWRITE = 1013 + ERROR_REGISTRY_RECOVERED = 1014 + ERROR_REGISTRY_CORRUPT = 1015 + ERROR_REGISTRY_IO_FAILED = 1016 + ERROR_NOT_REGISTRY_FILE = 1017 + ERROR_KEY_DELETED = 1018 + ERROR_NO_LOG_SPACE = 1019 + ERROR_KEY_HAS_CHILDREN = 1020 + ERROR_CHILD_MUST_BE_VOLATILE = 1021 + ERROR_NOTIFY_ENUM_DIR = 1022 + ERROR_DEPENDENT_SERVICES_RUNNING = 1051 + ERROR_INVALID_SERVICE_CONTROL = 1052 + ERROR_SERVICE_REQUEST_TIMEOUT = 1053 + ERROR_SERVICE_NO_THREAD = 1054 + ERROR_SERVICE_DATABASE_LOCKED = 1055 + ERROR_SERVICE_ALREADY_RUNNING = 1056 + ERROR_INVALID_SERVICE_ACCOUNT = 1057 + ERROR_SERVICE_DISABLED = 1058 + ERROR_CIRCULAR_DEPENDENCY = 1059 + ERROR_SERVICE_DOES_NOT_EXIST = 1060 + ERROR_SERVICE_CANNOT_ACCEPT_CTRL = 1061 + ERROR_SERVICE_NOT_ACTIVE = 1062 + ERROR_FAILED_SERVICE_CONTROLLER_CONNECT = 1063 + ERROR_EXCEPTION_IN_SERVICE = 1064 + ERROR_DATABASE_DOES_NOT_EXIST = 1065 + ERROR_SERVICE_SPECIFIC_ERROR = 1066 + ERROR_PROCESS_ABORTED = 1067 + ERROR_SERVICE_DEPENDENCY_FAIL = 1068 + ERROR_SERVICE_LOGON_FAILED = 1069 + ERROR_SERVICE_START_HANG = 1070 + ERROR_INVALID_SERVICE_LOCK = 1071 + ERROR_SERVICE_MARKED_FOR_DELETE = 1072 + ERROR_SERVICE_EXISTS = 1073 + ERROR_ALREADY_RUNNING_LKG = 1074 + ERROR_SERVICE_DEPENDENCY_DELETED = 1075 + ERROR_BOOT_ALREADY_ACCEPTED = 1076 + ERROR_SERVICE_NEVER_STARTED = 1077 + ERROR_DUPLICATE_SERVICE_NAME = 1078 + ERROR_DIFFERENT_SERVICE_ACCOUNT = 1079 + ERROR_CANNOT_DETECT_DRIVER_FAILURE = 1080 + ERROR_CANNOT_DETECT_PROCESS_ABORT = 1081 + ERROR_NO_RECOVERY_PROGRAM = 1082 + ERROR_SERVICE_NOT_IN_EXE = 1083 + ERROR_END_OF_MEDIA = 1100 + ERROR_FILEMARK_DETECTED = 1101 + ERROR_BEGINNING_OF_MEDIA = 1102 + ERROR_SETMARK_DETECTED = 1103 + ERROR_NO_DATA_DETECTED = 1104 + ERROR_PARTITION_FAILURE = 1105 + ERROR_INVALID_BLOCK_LENGTH = 1106 + ERROR_DEVICE_NOT_PARTITIONED = 1107 + ERROR_UNABLE_TO_LOCK_MEDIA = 1108 + ERROR_UNABLE_TO_UNLOAD_MEDIA = 1109 + ERROR_MEDIA_CHANGED = 1110 + ERROR_BUS_RESET = 1111 + ERROR_NO_MEDIA_IN_DRIVE = 1112 + ERROR_NO_UNICODE_TRANSLATION = 1113 + ERROR_DLL_INIT_FAILED = 1114 + ERROR_SHUTDOWN_IN_PROGRESS = 1115 + ERROR_NO_SHUTDOWN_IN_PROGRESS = 1116 + ERROR_IO_DEVICE = 1117 + ERROR_SERIAL_NO_DEVICE = 1118 + ERROR_IRQ_BUSY = 1119 + ERROR_MORE_WRITES = 1120 + ERROR_COUNTER_TIMEOUT = 1121 + ERROR_FLOPPY_ID_MARK_NOT_FOUND = 1122 + ERROR_FLOPPY_WRONG_CYLINDER = 1123 + ERROR_FLOPPY_UNKNOWN_ERROR = 1124 + ERROR_FLOPPY_BAD_REGISTERS = 1125 + ERROR_DISK_RECALIBRATE_FAILED = 1126 + ERROR_DISK_OPERATION_FAILED = 1127 + ERROR_DISK_RESET_FAILED = 1128 + ERROR_EOM_OVERFLOW = 1129 + ERROR_NOT_ENOUGH_SERVER_MEMORY = 1130 + ERROR_POSSIBLE_DEADLOCK = 1131 + ERROR_MAPPED_ALIGNMENT = 1132 + ERROR_SET_POWER_STATE_VETOED = 1140 + ERROR_SET_POWER_STATE_FAILED = 1141 + ERROR_TOO_MANY_LINKS = 1142 + ERROR_OLD_WIN_VERSION = 1150 + ERROR_APP_WRONG_OS = 1151 + ERROR_SINGLE_INSTANCE_APP = 1152 + ERROR_RMODE_APP = 1153 + ERROR_INVALID_DLL = 1154 + ERROR_NO_ASSOCIATION = 1155 + ERROR_DDE_FAIL = 1156 + ERROR_DLL_NOT_FOUND = 1157 + ERROR_NO_MORE_USER_HANDLES = 1158 + ERROR_MESSAGE_SYNC_ONLY = 1159 + ERROR_SOURCE_ELEMENT_EMPTY = 1160 + ERROR_DESTINATION_ELEMENT_FULL = 1161 + ERROR_ILLEGAL_ELEMENT_ADDRESS = 1162 + ERROR_MAGAZINE_NOT_PRESENT = 1163 + ERROR_DEVICE_REINITIALIZATION_NEEDED = 1164 + ERROR_DEVICE_REQUIRES_CLEANING = 1165 + ERROR_DEVICE_DOOR_OPEN = 1166 + ERROR_DEVICE_NOT_CONNECTED = 1167 + ERROR_NOT_FOUND = 1168 + ERROR_NO_MATCH = 1169 + ERROR_SET_NOT_FOUND = 1170 + ERROR_POINT_NOT_FOUND = 1171 + ERROR_NO_TRACKING_SERVICE = 1172 + ERROR_NO_VOLUME_ID = 1173 + ERROR_UNABLE_TO_REMOVE_REPLACED = 1175 + ERROR_UNABLE_TO_MOVE_REPLACEMENT = 1176 + ERROR_UNABLE_TO_MOVE_REPLACEMENT_2 = 1177 + ERROR_JOURNAL_DELETE_IN_PROGRESS = 1178 + ERROR_JOURNAL_NOT_ACTIVE = 1179 + ERROR_POTENTIAL_FILE_FOUND = 1180 + ERROR_JOURNAL_ENTRY_DELETED = 1181 + ERROR_BAD_DEVICE = 1200 + ERROR_CONNECTION_UNAVAIL = 1201 + ERROR_DEVICE_ALREADY_REMEMBERED = 1202 + ERROR_NO_NET_OR_BAD_PATH = 1203 + ERROR_BAD_PROVIDER = 1204 + ERROR_CANNOT_OPEN_PROFILE = 1205 + ERROR_BAD_PROFILE = 1206 + ERROR_NOT_CONTAINER = 1207 + ERROR_EXTENDED_ERROR = 1208 + ERROR_INVALID_GROUPNAME = 1209 + ERROR_INVALID_COMPUTERNAME = 1210 + ERROR_INVALID_EVENTNAME = 1211 + ERROR_INVALID_DOMAINNAME = 1212 + ERROR_INVALID_SERVICENAME = 1213 + ERROR_INVALID_NETNAME = 1214 + ERROR_INVALID_SHARENAME = 1215 + ERROR_INVALID_PASSWORDNAME = 1216 + ERROR_INVALID_MESSAGENAME = 1217 + ERROR_INVALID_MESSAGEDEST = 1218 + ERROR_SESSION_CREDENTIAL_CONFLICT = 1219 + ERROR_REMOTE_SESSION_LIMIT_EXCEEDED = 1220 + ERROR_DUP_DOMAINNAME = 1221 + ERROR_NO_NETWORK = 1222 + ERROR_CANCELLED = 1223 + ERROR_USER_MAPPED_FILE = 1224 + ERROR_CONNECTION_REFUSED = 1225 + ERROR_GRACEFUL_DISCONNECT = 1226 + ERROR_ADDRESS_ALREADY_ASSOCIATED = 1227 + ERROR_ADDRESS_NOT_ASSOCIATED = 1228 + ERROR_CONNECTION_INVALID = 1229 + ERROR_CONNECTION_ACTIVE = 1230 + ERROR_NETWORK_UNREACHABLE = 1231 + ERROR_HOST_UNREACHABLE = 1232 + ERROR_PROTOCOL_UNREACHABLE = 1233 + ERROR_PORT_UNREACHABLE = 1234 + ERROR_REQUEST_ABORTED = 1235 + ERROR_CONNECTION_ABORTED = 1236 + ERROR_RETRY = 1237 + ERROR_CONNECTION_COUNT_LIMIT = 1238 + ERROR_LOGIN_TIME_RESTRICTION = 1239 + ERROR_LOGIN_WKSTA_RESTRICTION = 1240 + ERROR_INCORRECT_ADDRESS = 1241 + ERROR_ALREADY_REGISTERED = 1242 + ERROR_SERVICE_NOT_FOUND = 1243 + ERROR_NOT_AUTHENTICATED = 1244 + ERROR_NOT_LOGGED_ON = 1245 + ERROR_CONTINUE = 1246 + ERROR_ALREADY_INITIALIZED = 1247 + ERROR_NO_MORE_DEVICES = 1248 + ERROR_NO_SUCH_SITE = 1249 + ERROR_DOMAIN_CONTROLLER_EXISTS = 1250 + ERROR_ONLY_IF_CONNECTED = 1251 + ERROR_OVERRIDE_NOCHANGES = 1252 + ERROR_BAD_USER_PROFILE = 1253 + ERROR_NOT_SUPPORTED_ON_SBS = 1254 + ERROR_SERVER_SHUTDOWN_IN_PROGRESS = 1255 + ERROR_HOST_DOWN = 1256 + ERROR_ACCESS_DISABLED_BY_POLICY = 1260 + ERROR_REG_NAT_CONSUMPTION = 1261 + ERROR_PKINIT_FAILURE = 1263 + ERROR_SMARTCARD_SUBSYSTEM_FAILURE = 1264 + ERROR_DOWNGRADE_DETECTED = 1265 + ERROR_MACHINE_LOCKED = 1271 + ERROR_CALLBACK_SUPPLIED_INVALID_DATA = 1273 + ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED= 1274 + ERROR_DRIVER_BLOCKED = 1275 + ERROR_INVALID_IMPORT_OF_NON_DLL = 1276 + ERROR_NOT_ALL_ASSIGNED = 1300 + ERROR_SOME_NOT_MAPPED = 1301 + ERROR_NO_QUOTAS_FOR_ACCOUNT = 1302 + ERROR_LOCAL_USER_SESSION_KEY = 1303 + ERROR_NULL_LM_PASSWORD = 1304 + ERROR_UNKNOWN_REVISION = 1305 + ERROR_REVISION_MISMATCH = 1306 + ERROR_INVALID_OWNER = 1307 + ERROR_INVALID_PRIMARY_GROUP = 1308 + ERROR_NO_IMPERSONATION_TOKEN = 1309 + ERROR_CANT_DISABLE_MANDATORY = 1310 + ERROR_NO_LOGON_SERVERS = 1311 + ERROR_NO_SUCH_LOGON_SESSION = 1312 + ERROR_NO_SUCH_PRIVILEGE = 1313 + ERROR_PRIVILEGE_NOT_HELD = 1314 + ERROR_INVALID_ACCOUNT_NAME = 1315 + ERROR_USER_EXISTS = 1316 + ERROR_NO_SUCH_USER = 1317 + ERROR_GROUP_EXISTS = 1318 + ERROR_NO_SUCH_GROUP = 1319 + ERROR_MEMBER_IN_GROUP = 1320 + ERROR_MEMBER_NOT_IN_GROUP = 1321 + ERROR_LAST_ADMIN = 1322 + ERROR_WRONG_PASSWORD = 1323 + ERROR_ILL_FORMED_PASSWORD = 1324 + ERROR_PASSWORD_RESTRICTION = 1325 + ERROR_LOGON_FAILURE = 1326 + ERROR_ACCOUNT_RESTRICTION = 1327 + ERROR_INVALID_LOGON_HOURS = 1328 + ERROR_INVALID_WORKSTATION = 1329 + ERROR_PASSWORD_EXPIRED = 1330 + ERROR_ACCOUNT_DISABLED = 1331 + ERROR_NONE_MAPPED = 1332 + ERROR_TOO_MANY_LUIDS_REQUESTED = 1333 + ERROR_LUIDS_EXHAUSTED = 1334 + ERROR_INVALID_SUB_AUTHORITY = 1335 + ERROR_INVALID_ACL = 1336 + ERROR_INVALID_SID = 1337 + ERROR_INVALID_SECURITY_DESCR = 1338 + ERROR_BAD_INHERITANCE_ACL = 1340 + ERROR_SERVER_DISABLED = 1341 + ERROR_SERVER_NOT_DISABLED = 1342 + ERROR_INVALID_ID_AUTHORITY = 1343 + ERROR_ALLOTTED_SPACE_EXCEEDED = 1344 + ERROR_INVALID_GROUP_ATTRIBUTES = 1345 + ERROR_BAD_IMPERSONATION_LEVEL = 1346 + ERROR_CANT_OPEN_ANONYMOUS = 1347 + ERROR_BAD_VALIDATION_CLASS = 1348 + ERROR_BAD_TOKEN_TYPE = 1349 + ERROR_NO_SECURITY_ON_OBJECT = 1350 + ERROR_CANT_ACCESS_DOMAIN_INFO = 1351 + ERROR_INVALID_SERVER_STATE = 1352 + ERROR_INVALID_DOMAIN_STATE = 1353 + ERROR_INVALID_DOMAIN_ROLE = 1354 + ERROR_NO_SUCH_DOMAIN = 1355 + ERROR_DOMAIN_EXISTS = 1356 + ERROR_DOMAIN_LIMIT_EXCEEDED = 1357 + ERROR_INTERNAL_DB_CORRUPTION = 1358 + ERROR_INTERNAL_ERROR = 1359 + ERROR_GENERIC_NOT_MAPPED = 1360 + ERROR_BAD_DESCRIPTOR_FORMAT = 1361 + ERROR_NOT_LOGON_PROCESS = 1362 + ERROR_LOGON_SESSION_EXISTS = 1363 + ERROR_NO_SUCH_PACKAGE = 1364 + ERROR_BAD_LOGON_SESSION_STATE = 1365 + ERROR_LOGON_SESSION_COLLISION = 1366 + ERROR_INVALID_LOGON_TYPE = 1367 + ERROR_CANNOT_IMPERSONATE = 1368 + ERROR_RXACT_INVALID_STATE = 1369 + ERROR_RXACT_COMMIT_FAILURE = 1370 + ERROR_SPECIAL_ACCOUNT = 1371 + ERROR_SPECIAL_GROUP = 1372 + ERROR_SPECIAL_USER = 1373 + ERROR_MEMBERS_PRIMARY_GROUP = 1374 + ERROR_TOKEN_ALREADY_IN_USE = 1375 + ERROR_NO_SUCH_ALIAS = 1376 + ERROR_MEMBER_NOT_IN_ALIAS = 1377 + ERROR_MEMBER_IN_ALIAS = 1378 + ERROR_ALIAS_EXISTS = 1379 + ERROR_LOGON_NOT_GRANTED = 1380 + ERROR_TOO_MANY_SECRETS = 1381 + ERROR_SECRET_TOO_LONG = 1382 + ERROR_INTERNAL_DB_ERROR = 1383 + ERROR_TOO_MANY_CONTEXT_IDS = 1384 + ERROR_LOGON_TYPE_NOT_GRANTED = 1385 + ERROR_NT_CROSS_ENCRYPTION_REQUIRED = 1386 + ERROR_NO_SUCH_MEMBER = 1387 + ERROR_INVALID_MEMBER = 1388 + ERROR_TOO_MANY_SIDS = 1389 + ERROR_LM_CROSS_ENCRYPTION_REQUIRED = 1390 + ERROR_NO_INHERITANCE = 1391 + ERROR_FILE_CORRUPT = 1392 + ERROR_DISK_CORRUPT = 1393 + ERROR_NO_USER_SESSION_KEY = 1394 + ERROR_LICENSE_QUOTA_EXCEEDED = 1395 + ERROR_WRONG_TARGET_NAME = 1396 + ERROR_MUTUAL_AUTH_FAILED = 1397 + ERROR_TIME_SKEW = 1398 + ERROR_CURRENT_DOMAIN_NOT_ALLOWED = 1399 + ERROR_INVALID_WINDOW_HANDLE = 1400 + ERROR_INVALID_MENU_HANDLE = 1401 + ERROR_INVALID_CURSOR_HANDLE = 1402 + ERROR_INVALID_ACCEL_HANDLE = 1403 + ERROR_INVALID_HOOK_HANDLE = 1404 + ERROR_INVALID_DWP_HANDLE = 1405 + ERROR_TLW_WITH_WSCHILD = 1406 + ERROR_CANNOT_FIND_WND_CLASS = 1407 + ERROR_WINDOW_OF_OTHER_THREAD = 1408 + ERROR_HOTKEY_ALREADY_REGISTERED = 1409 + ERROR_CLASS_ALREADY_EXISTS = 1410 + ERROR_CLASS_DOES_NOT_EXIST = 1411 + ERROR_CLASS_HAS_WINDOWS = 1412 + ERROR_INVALID_INDEX = 1413 + ERROR_INVALID_ICON_HANDLE = 1414 + ERROR_PRIVATE_DIALOG_INDEX = 1415 + ERROR_LISTBOX_ID_NOT_FOUND = 1416 + ERROR_NO_WILDCARD_CHARACTERS = 1417 + ERROR_CLIPBOARD_NOT_OPEN = 1418 + ERROR_HOTKEY_NOT_REGISTERED = 1419 + ERROR_WINDOW_NOT_DIALOG = 1420 + ERROR_CONTROL_ID_NOT_FOUND = 1421 + ERROR_INVALID_COMBOBOX_MESSAGE = 1422 + ERROR_WINDOW_NOT_COMBOBOX = 1423 + ERROR_INVALID_EDIT_HEIGHT = 1424 + ERROR_DC_NOT_FOUND = 1425 + ERROR_INVALID_HOOK_FILTER = 1426 + ERROR_INVALID_FILTER_PROC = 1427 + ERROR_HOOK_NEEDS_HMOD = 1428 + ERROR_GLOBAL_ONLY_HOOK = 1429 + ERROR_JOURNAL_HOOK_SET = 1430 + ERROR_HOOK_NOT_INSTALLED = 1431 + ERROR_INVALID_LB_MESSAGE = 1432 + ERROR_SETCOUNT_ON_BAD_LB = 1433 + ERROR_LB_WITHOUT_TABSTOPS = 1434 + ERROR_DESTROY_OBJECT_OF_OTHER_THREAD = 1435 + ERROR_CHILD_WINDOW_MENU = 1436 + ERROR_NO_SYSTEM_MENU = 1437 + ERROR_INVALID_MSGBOX_STYLE = 1438 + ERROR_INVALID_SPI_VALUE = 1439 + ERROR_SCREEN_ALREADY_LOCKED = 1440 + ERROR_HWNDS_HAVE_DIFF_PARENT = 1441 + ERROR_NOT_CHILD_WINDOW = 1442 + ERROR_INVALID_GW_COMMAND = 1443 + ERROR_INVALID_THREAD_ID = 1444 + ERROR_NON_MDICHILD_WINDOW = 1445 + ERROR_POPUP_ALREADY_ACTIVE = 1446 + ERROR_NO_SCROLLBARS = 1447 + ERROR_INVALID_SCROLLBAR_RANGE = 1448 + ERROR_INVALID_SHOWWIN_COMMAND = 1449 + ERROR_NO_SYSTEM_RESOURCES = 1450 + ERROR_NONPAGED_SYSTEM_RESOURCES = 1451 + ERROR_PAGED_SYSTEM_RESOURCES = 1452 + ERROR_WORKING_SET_QUOTA = 1453 + ERROR_PAGEFILE_QUOTA = 1454 + ERROR_COMMITMENT_LIMIT = 1455 + ERROR_MENU_ITEM_NOT_FOUND = 1456 + ERROR_INVALID_KEYBOARD_HANDLE = 1457 + ERROR_HOOK_TYPE_NOT_ALLOWED = 1458 + ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION = 1459 + ERROR_TIMEOUT = 1460 + ERROR_INVALID_MONITOR_HANDLE = 1461 + ERROR_EVENTLOG_FILE_CORRUPT = 1500 + ERROR_EVENTLOG_CANT_START = 1501 + ERROR_LOG_FILE_FULL = 1502 + ERROR_EVENTLOG_FILE_CHANGED = 1503 + ERROR_INVALID_TASK_NAME = 1550 + ERROR_INVALID_TASK_INDEX = 1551 + ERROR_THREAD_ALREADY_IN_TASK = 1552 + ERROR_INSTALL_SERVICE_FAILURE = 1601 + ERROR_INSTALL_USEREXIT = 1602 + ERROR_INSTALL_FAILURE = 1603 + ERROR_INSTALL_SUSPEND = 1604 + ERROR_UNKNOWN_PRODUCT = 1605 + ERROR_UNKNOWN_FEATURE = 1606 + ERROR_UNKNOWN_COMPONENT = 1607 + ERROR_UNKNOWN_PROPERTY = 1608 + ERROR_INVALID_HANDLE_STATE = 1609 + ERROR_BAD_CONFIGURATION = 1610 + ERROR_INDEX_ABSENT = 1611 + ERROR_INSTALL_SOURCE_ABSENT = 1612 + ERROR_INSTALL_PACKAGE_VERSION = 1613 + ERROR_PRODUCT_UNINSTALLED = 1614 + ERROR_BAD_QUERY_SYNTAX = 1615 + ERROR_INVALID_FIELD = 1616 + ERROR_DEVICE_REMOVED = 1617 + ERROR_INSTALL_ALREADY_RUNNING = 1618 + ERROR_INSTALL_PACKAGE_OPEN_FAILED = 1619 + ERROR_INSTALL_PACKAGE_INVALID = 1620 + ERROR_INSTALL_UI_FAILURE = 1621 + ERROR_INSTALL_LOG_FAILURE = 1622 + ERROR_INSTALL_LANGUAGE_UNSUPPORTED = 1623 + ERROR_INSTALL_TRANSFORM_FAILURE = 1624 + ERROR_INSTALL_PACKAGE_REJECTED = 1625 + ERROR_FUNCTION_NOT_CALLED = 1626 + ERROR_FUNCTION_FAILED = 1627 + ERROR_INVALID_TABLE = 1628 + ERROR_DATATYPE_MISMATCH = 1629 + ERROR_UNSUPPORTED_TYPE = 1630 + ERROR_CREATE_FAILED = 1631 + ERROR_INSTALL_TEMP_UNWRITABLE = 1632 + ERROR_INSTALL_PLATFORM_UNSUPPORTED = 1633 + ERROR_INSTALL_NOTUSED = 1634 + ERROR_PATCH_PACKAGE_OPEN_FAILED = 1635 + ERROR_PATCH_PACKAGE_INVALID = 1636 + ERROR_PATCH_PACKAGE_UNSUPPORTED = 1637 + ERROR_PRODUCT_VERSION = 1638 + ERROR_INVALID_COMMAND_LINE = 1639 + ERROR_INSTALL_REMOTE_DISALLOWED = 1640 + ERROR_SUCCESS_REBOOT_INITIATED = 1641 + ERROR_UNKNOWN_PATCH = 1647 + RPC_S_INVALID_STRING_BINDING = 1700 + RPC_S_WRONG_KIND_OF_BINDING = 1701 + RPC_S_INVALID_BINDING = 1702 + RPC_S_PROTSEQ_NOT_SUPPORTED = 1703 + RPC_S_INVALID_RPC_PROTSEQ = 1704 + RPC_S_INVALID_STRING_UUID = 1705 + RPC_S_INVALID_ENDPOINT_FORMAT = 1706 + RPC_S_INVALID_NET_ADDR = 1707 + RPC_S_NO_ENDPOINT_FOUND = 1708 + RPC_S_INVALID_TIMEOUT = 1709 + RPC_S_OBJECT_NOT_FOUND = 1710 + RPC_S_ALREADY_REGISTERED = 1711 + RPC_S_TYPE_ALREADY_REGISTERED = 1712 + RPC_S_ALREADY_LISTENING = 1713 + RPC_S_NO_PROTSEQS_REGISTERED = 1714 + RPC_S_NOT_LISTENING = 1715 + RPC_S_UNKNOWN_MGR_TYPE = 1716 + RPC_S_UNKNOWN_IF = 1717 + RPC_S_NO_BINDINGS = 1718 + RPC_S_NO_PROTSEQS = 1719 + RPC_S_CANT_CREATE_ENDPOINT = 1720 + RPC_S_OUT_OF_RESOURCES = 1721 + RPC_S_SERVER_UNAVAILABLE = 1722 + RPC_S_SERVER_TOO_BUSY = 1723 + RPC_S_INVALID_NETWORK_OPTIONS = 1724 + RPC_S_NO_CALL_ACTIVE = 1725 + RPC_S_CALL_FAILED = 1726 + RPC_S_CALL_FAILED_DNE = 1727 + RPC_S_PROTOCOL_ERROR = 1728 + RPC_S_UNSUPPORTED_TRANS_SYN = 1730 + RPC_S_UNSUPPORTED_TYPE = 1732 + RPC_S_INVALID_TAG = 1733 + RPC_S_INVALID_BOUND = 1734 + RPC_S_NO_ENTRY_NAME = 1735 + RPC_S_INVALID_NAME_SYNTAX = 1736 + RPC_S_UNSUPPORTED_NAME_SYNTAX = 1737 + RPC_S_UUID_NO_ADDRESS = 1739 + RPC_S_DUPLICATE_ENDPOINT = 1740 + RPC_S_UNKNOWN_AUTHN_TYPE = 1741 + RPC_S_MAX_CALLS_TOO_SMALL = 1742 + RPC_S_STRING_TOO_LONG = 1743 + RPC_S_PROTSEQ_NOT_FOUND = 1744 + RPC_S_PROCNUM_OUT_OF_RANGE = 1745 + RPC_S_BINDING_HAS_NO_AUTH = 1746 + RPC_S_UNKNOWN_AUTHN_SERVICE = 1747 + RPC_S_UNKNOWN_AUTHN_LEVEL = 1748 + RPC_S_INVALID_AUTH_IDENTITY = 1749 + RPC_S_UNKNOWN_AUTHZ_SERVICE = 1750 + EPT_S_INVALID_ENTRY = 1751 + EPT_S_CANT_PERFORM_OP = 1752 + EPT_S_NOT_REGISTERED = 1753 + RPC_S_NOTHING_TO_EXPORT = 1754 + RPC_S_INCOMPLETE_NAME = 1755 + RPC_S_INVALID_VERS_OPTION = 1756 + RPC_S_NO_MORE_MEMBERS = 1757 + RPC_S_NOT_ALL_OBJS_UNEXPORTED = 1758 + RPC_S_INTERFACE_NOT_FOUND = 1759 + RPC_S_ENTRY_ALREADY_EXISTS = 1760 + RPC_S_ENTRY_NOT_FOUND = 1761 + RPC_S_NAME_SERVICE_UNAVAILABLE = 1762 + RPC_S_INVALID_NAF_ID = 1763 + RPC_S_CANNOT_SUPPORT = 1764 + RPC_S_NO_CONTEXT_AVAILABLE = 1765 + RPC_S_INTERNAL_ERROR = 1766 + RPC_S_ZERO_DIVIDE = 1767 + RPC_S_ADDRESS_ERROR = 1768 + RPC_S_FP_DIV_ZERO = 1769 + RPC_S_FP_UNDERFLOW = 1770 + RPC_S_FP_OVERFLOW = 1771 + RPC_X_NO_MORE_ENTRIES = 1772 + RPC_X_SS_CHAR_TRANS_OPEN_FAIL = 1773 + RPC_X_SS_CHAR_TRANS_SHORT_FILE = 1774 + RPC_X_SS_IN_NULL_CONTEXT = 1775 + RPC_X_SS_CONTEXT_DAMAGED = 1777 + RPC_X_SS_HANDLES_MISMATCH = 1778 + RPC_X_SS_CANNOT_GET_CALL_HANDLE = 1779 + RPC_X_NULL_REF_POINTER = 1780 + RPC_X_ENUM_VALUE_OUT_OF_RANGE = 1781 + RPC_X_BYTE_COUNT_TOO_SMALL = 1782 + RPC_X_BAD_STUB_DATA = 1783 + ERROR_INVALID_USER_BUFFER = 1784 + ERROR_UNRECOGNIZED_MEDIA = 1785 + ERROR_NO_TRUST_LSA_SECRET = 1786 + ERROR_NO_TRUST_SAM_ACCOUNT = 1787 + ERROR_TRUSTED_DOMAIN_FAILURE = 1788 + ERROR_TRUSTED_RELATIONSHIP_FAILURE = 1789 + ERROR_TRUST_FAILURE = 1790 + RPC_S_CALL_IN_PROGRESS = 1791 + ERROR_NETLOGON_NOT_STARTED = 1792 + ERROR_ACCOUNT_EXPIRED = 1793 + ERROR_REDIRECTOR_HAS_OPEN_HANDLES = 1794 + ERROR_PRINTER_DRIVER_ALREADY_INSTALLED= 1795 + ERROR_UNKNOWN_PORT = 1796 + ERROR_UNKNOWN_PRINTER_DRIVER = 1797 + ERROR_UNKNOWN_PRINTPROCESSOR = 1798 + ERROR_INVALID_SEPARATOR_FILE = 1799 + ERROR_INVALID_PRIORITY = 1800 + ERROR_INVALID_PRINTER_NAME = 1801 + ERROR_PRINTER_ALREADY_EXISTS = 1802 + ERROR_INVALID_PRINTER_COMMAND = 1803 + ERROR_INVALID_DATATYPE = 1804 + ERROR_INVALID_ENVIRONMENT = 1805 + RPC_S_NO_MORE_BINDINGS = 1806 + ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT = 1807 + ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT = 1808 + ERROR_NOLOGON_SERVER_TRUST_ACCOUNT = 1809 + ERROR_DOMAIN_TRUST_INCONSISTENT = 1810 + ERROR_SERVER_HAS_OPEN_HANDLES = 1811 + ERROR_RESOURCE_DATA_NOT_FOUND = 1812 + ERROR_RESOURCE_TYPE_NOT_FOUND = 1813 + ERROR_RESOURCE_NAME_NOT_FOUND = 1814 + ERROR_RESOURCE_LANG_NOT_FOUND = 1815 + ERROR_NOT_ENOUGH_QUOTA = 1816 + RPC_S_NO_INTERFACES = 1817 + RPC_S_CALL_CANCELLED = 1818 + RPC_S_BINDING_INCOMPLETE = 1819 + RPC_S_COMM_FAILURE = 1820 + RPC_S_UNSUPPORTED_AUTHN_LEVEL = 1821 + RPC_S_NO_PRINC_NAME = 1822 + RPC_S_NOT_RPC_ERROR = 1823 + RPC_S_UUID_LOCAL_ONLY = 1824 + RPC_S_SEC_PKG_ERROR = 1825 + RPC_S_NOT_CANCELLED = 1826 + RPC_X_INVALID_ES_ACTION = 1827 + RPC_X_WRONG_ES_VERSION = 1828 + RPC_X_WRONG_STUB_VERSION = 1829 + RPC_X_INVALID_PIPE_OBJECT = 1830 + RPC_X_WRONG_PIPE_ORDER = 1831 + RPC_X_WRONG_PIPE_VERSION = 1832 + RPC_S_GROUP_MEMBER_NOT_FOUND = 1898 + EPT_S_CANT_CREATE = 1899 + RPC_S_INVALID_OBJECT = 1900 + ERROR_INVALID_TIME = 1901 + ERROR_INVALID_FORM_NAME = 1902 + ERROR_INVALID_FORM_SIZE = 1903 + ERROR_ALREADY_WAITING = 1904 + ERROR_PRINTER_DELETED = 1905 + ERROR_INVALID_PRINTER_STATE = 1906 + ERROR_PASSWORD_MUST_CHANGE = 1907 + ERROR_DOMAIN_CONTROLLER_NOT_FOUND = 1908 + ERROR_ACCOUNT_LOCKED_OUT = 1909 + OR_INVALID_OXID = 1910 + OR_INVALID_OID = 1911 + OR_INVALID_SET = 1912 + RPC_S_SEND_INCOMPLETE = 1913 + RPC_S_INVALID_ASYNC_HANDLE = 1914 + RPC_S_INVALID_ASYNC_CALL = 1915 + RPC_X_PIPE_CLOSED = 1916 + RPC_X_PIPE_DISCIPLINE_ERROR = 1917 + RPC_X_PIPE_EMPTY = 1918 + ERROR_NO_SITENAME = 1919 + ERROR_CANT_ACCESS_FILE = 1920 + ERROR_CANT_RESOLVE_FILENAME = 1921 + RPC_S_ENTRY_TYPE_MISMATCH = 1922 + RPC_S_NOT_ALL_OBJS_EXPORTED = 1923 + RPC_S_INTERFACE_NOT_EXPORTED = 1924 + RPC_S_PROFILE_NOT_ADDED = 1925 + RPC_S_PRF_ELT_NOT_ADDED = 1926 + RPC_S_PRF_ELT_NOT_REMOVED = 1927 + RPC_S_GRP_ELT_NOT_ADDED = 1928 + RPC_S_GRP_ELT_NOT_REMOVED = 1929 + ERROR_KM_DRIVER_BLOCKED = 1930 + ERROR_CONTEXT_EXPIRED = 1931 + ERROR_PER_USER_TRUST_QUOTA_EXCEEDED = 1932 + ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED = 1933 + ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED= 1934 + ERROR_AUTHENTICATION_FIREWALL_FAILED = 1935 + ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED= 1936 + ERROR_INVALID_PIXEL_FORMAT = 2000 + ERROR_BAD_DRIVER = 2001 + ERROR_INVALID_WINDOW_STYLE = 2002 + ERROR_METAFILE_NOT_SUPPORTED = 2003 + ERROR_TRANSFORM_NOT_SUPPORTED = 2004 + ERROR_CLIPPING_NOT_SUPPORTED = 2005 + ERROR_INVALID_CMM = 2010 + ERROR_INVALID_PROFILE = 2011 + ERROR_TAG_NOT_FOUND = 2012 + ERROR_TAG_NOT_PRESENT = 2013 + ERROR_DUPLICATE_TAG = 2014 + ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE = 2015 + ERROR_PROFILE_NOT_FOUND = 2016 + ERROR_INVALID_COLORSPACE = 2017 + ERROR_ICM_NOT_ENABLED = 2018 + ERROR_DELETING_ICM_XFORM = 2019 + ERROR_INVALID_TRANSFORM = 2020 + ERROR_COLORSPACE_MISMATCH = 2021 + ERROR_INVALID_COLORINDEX = 2022 + ERROR_CONNECTED_OTHER_PASSWORD = 2108 + ERROR_BAD_USERNAME = 2202 + ERROR_NOT_CONNECTED = 2250 + ERROR_OPEN_FILES = 2401 + ERROR_ACTIVE_CONNECTIONS = 2402 + ERROR_DEVICE_IN_USE = 2404 + ERROR_UNKNOWN_PRINT_MONITOR = 3000 + + ERROR_USER_DEFINED_BASE = 0xF000 + + # Flags for FormatMessage function: + + FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100 + FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200 + FORMAT_MESSAGE_FROM_STRING = 0x00000400 + FORMAT_MESSAGE_FROM_HMODULE = 0x00000800 + FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000 + FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000 + FORMAT_MESSAGE_MAX_WIDTH_MASK = 0x000000FF + + # Set/GetErrorMode values: + + SEM_FAILCRITICALERRORS = 0x0001 + SEM_NOALIGNMENTFAULTEXCEPT = 0x0004 + SEM_NOGPFAULTERRORBOX = 0x0002 + SEM_NOOPENFILEERRORBOX = 0x8000 + + ############################################### + # Win32 API Bindings + ############################################### + + ffi_lib 'kernel32', 'user32' + +=begin +DWORD WINAPI FormatMessage( + __in DWORD dwFlags, + __in_opt LPCVOID lpSource, + __in DWORD dwMessageId, + __in DWORD dwLanguageId, + __out LPTSTR lpBuffer, + __in DWORD nSize, + __in_opt va_list *Arguments +); +=end + safe_attach_function :FormatMessageA, [:DWORD, :LPCVOID, :DWORD, :DWORD, :LPTSTR, :DWORD, :varargs], :DWORD + safe_attach_function :FormatMessageW, [:DWORD, :LPCVOID, :DWORD, :DWORD, :LPWSTR, :DWORD, :varargs], :DWORD + +=begin +DWORD WINAPI GetLastError(void); +=end + safe_attach_function :GetLastError, [], :DWORD +=begin +void WINAPI SetLastError( + __in DWORD dwErrCode +); +=end + safe_attach_function :SetLastError, [:DWORD], :void + safe_attach_function :SetLastErrorEx, [:DWORD, :DWORD], :void +=begin +UINT WINAPI GetErrorMode(void);s +=end + safe_attach_function :GetErrorMode, [], :uint +=begin +UINT WINAPI SetErrorMode( + __in UINT uMode +); +=end + safe_attach_function :SetErrorMode, [:UINT], :UINT + + end + end + end +end diff --git a/lib/chef/win32/api/file.rb b/lib/chef/win32/api/file.rb new file mode 100644 index 0000000000..41a128ea7e --- /dev/null +++ b/lib/chef/win32/api/file.rb @@ -0,0 +1,535 @@ +# +# Author:: Seth Chisamore () +# Author:: Mark Mzyk () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/api' +require 'chef/win32/api/security' +require 'chef/win32/api/system' + +class Chef + module ReservedNames::Win32 + module API + module File + extend Chef::ReservedNames::Win32::API + include Chef::ReservedNames::Win32::API::Security + include Chef::ReservedNames::Win32::API::System + + ############################################### + # Win32 API Constants + ############################################### + + FILE_ATTRIBUTE_READONLY = 0x00000001 + FILE_ATTRIBUTE_HIDDEN = 0x00000002 + FILE_ATTRIBUTE_SYSTEM = 0x00000004 + FILE_ATTRIBUTE_DIRECTORY = 0x00000010 + FILE_ATTRIBUTE_ARCHIVE = 0x00000020 + FILE_ATTRIBUTE_DEVICE = 0x00000040 + FILE_ATTRIBUTE_NORMAL = 0x00000080 + FILE_ATTRIBUTE_TEMPORARY = 0x00000100 + FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200 + FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400 + FILE_ATTRIBUTE_COMPRESSED = 0x00000800 + FILE_ATTRIBUTE_OFFLINE = 0x00001000 + FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000 + FILE_ATTRIBUTE_ENCRYPTED = 0x00004000 + FILE_ATTRIBUTE_VIRTUAL = 0x00010000 + INVALID_FILE_ATTRIBUTES = 0xFFFFFFFF + + FILE_FLAG_WRITE_THROUGH = 0x80000000 + FILE_FLAG_OVERLAPPED = 0x40000000 + FILE_FLAG_NO_BUFFERING = 0x20000000 + FILE_FLAG_RANDOM_ACCESS = 0x10000000 + FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000 + FILE_FLAG_DELETE_ON_CLOSE = 0x04000000 + FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 + FILE_FLAG_POSIX_SEMANTICS = 0x01000000 + FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000 + FILE_FLAG_OPEN_NO_RECALL = 0x00100000 + FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000 + + INVALID_HANDLE_VALUE = 0xFFFFFFFF + MAX_PATH = 260 + + SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1 + + FILE_NAME_NORMALIZED = 0x0 + FILE_NAME_OPENED = 0x8 + + # TODO add the rest of these CONSTS + FILE_SHARE_READ = 0x00000001 + OPEN_EXISTING = 3 + + # DeviceIoControl control codes + # ----------------------------- + FILE_DEVICE_BEEP = 0x00000001 + FILE_DEVICE_CD_ROM = 0x00000002 + FILE_DEVICE_CD_ROM_FILE_SYSTEM = 0x00000003 + FILE_DEVICE_CONTROLLER = 0x00000004 + FILE_DEVICE_DATALINK = 0x00000005 + FILE_DEVICE_DFS = 0x00000006 + FILE_DEVICE_DISK = 0x00000007 + FILE_DEVICE_DISK_FILE_SYSTEM = 0x00000008 + FILE_DEVICE_FILE_SYSTEM = 0x00000009 + FILE_DEVICE_INPORT_PORT = 0x0000000a + FILE_DEVICE_KEYBOARD = 0x0000000b + FILE_DEVICE_MAILSLOT = 0x0000000c + FILE_DEVICE_MIDI_IN = 0x0000000d + FILE_DEVICE_MIDI_OUT = 0x0000000e + FILE_DEVICE_MOUSE = 0x0000000f + FILE_DEVICE_MULTI_UNC_PROVIDER = 0x00000010 + FILE_DEVICE_NAMED_PIPE = 0x00000011 + FILE_DEVICE_NETWORK = 0x00000012 + FILE_DEVICE_NETWORK_BROWSER = 0x00000013 + FILE_DEVICE_NETWORK_FILE_SYSTEM = 0x00000014 + FILE_DEVICE_NULL = 0x00000015 + FILE_DEVICE_PARALLEL_PORT = 0x00000016 + FILE_DEVICE_PHYSICAL_NETCARD = 0x00000017 + FILE_DEVICE_PRINTER = 0x00000018 + FILE_DEVICE_SCANNER = 0x00000019 + FILE_DEVICE_SERIAL_MOUSE_PORT = 0x0000001a + FILE_DEVICE_SERIAL_PORT = 0x0000001b + FILE_DEVICE_SCREEN = 0x0000001c + FILE_DEVICE_SOUND = 0x0000001d + FILE_DEVICE_STREAMS = 0x0000001e + FILE_DEVICE_TAPE = 0x0000001f + FILE_DEVICE_TAPE_FILE_SYSTEM = 0x00000020 + FILE_DEVICE_TRANSPORT = 0x00000021 + FILE_DEVICE_UNKNOWN = 0x00000022 + FILE_DEVICE_VIDEO = 0x00000023 + FILE_DEVICE_VIRTUAL_DISK = 0x00000024 + FILE_DEVICE_WAVE_IN = 0x00000025 + FILE_DEVICE_WAVE_OUT = 0x00000026 + FILE_DEVICE_8042_PORT = 0x00000027 + FILE_DEVICE_NETWORK_REDIRECTOR = 0x00000028 + FILE_DEVICE_BATTERY = 0x00000029 + FILE_DEVICE_BUS_EXTENDER = 0x0000002a + FILE_DEVICE_MODEM = 0x0000002b + FILE_DEVICE_VDM = 0x0000002c + FILE_DEVICE_MASS_STORAGE = 0x0000002d + FILE_DEVICE_SMB = 0x0000002e + FILE_DEVICE_KS = 0x0000002f + FILE_DEVICE_CHANGER = 0x00000030 + FILE_DEVICE_SMARTCARD = 0x00000031 + FILE_DEVICE_ACPI = 0x00000032 + FILE_DEVICE_DVD = 0x00000033 + FILE_DEVICE_FULLSCREEN_VIDEO = 0x00000034 + FILE_DEVICE_DFS_FILE_SYSTEM = 0x00000035 + FILE_DEVICE_DFS_VOLUME = 0x00000036 + FILE_DEVICE_SERENUM = 0x00000037 + FILE_DEVICE_TERMSRV = 0x00000038 + FILE_DEVICE_KSEC = 0x00000039 + FILE_DEVICE_FIPS = 0x0000003A + FILE_DEVICE_INFINIBAND = 0x0000003B + FILE_DEVICE_VMBUS = 0x0000003E + FILE_DEVICE_CRYPT_PROVIDER = 0x0000003F + FILE_DEVICE_WPD = 0x00000040 + FILE_DEVICE_BLUETOOTH = 0x00000041 + FILE_DEVICE_MT_COMPOSITE = 0x00000042 + FILE_DEVICE_MT_TRANSPORT = 0x00000043 + FILE_DEVICE_BIOMETRIC = 0x00000044 + FILE_DEVICE_PMI = 0x00000045 + + # Methods + METHOD_BUFFERED = 0 + METHOD_IN_DIRECT = 1 + METHOD_OUT_DIRECT = 2 + METHOD_NEITHER = 3 + METHOD_DIRECT_TO_HARDWARE = METHOD_IN_DIRECT + METHOD_DIRECT_FROM_HARDWARE = METHOD_OUT_DIRECT + + # Access + FILE_ANY_ACCESS = 0 + FILE_SPECIAL_ACCESS = FILE_ANY_ACCESS + FILE_READ_ACCESS = 0x0001 + FILE_WRITE_ACCESS = 0x0002 + + def self.CTL_CODE( device_type, function, method, access ) + (device_type << 16) | (access << 14) | (function << 2) | method + end + + FSCTL_GET_REPARSE_POINT = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) + + # Reparse point tags + IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003 + IO_REPARSE_TAG_HSM = 0xC0000004 + IO_REPARSE_TAG_HSM2 = 0x80000006 + IO_REPARSE_TAG_SIS = 0x80000007 + IO_REPARSE_TAG_WIM = 0x80000008 + IO_REPARSE_TAG_CSV = 0x80000009 + IO_REPARSE_TAG_DFS = 0x8000000A + IO_REPARSE_TAG_SYMLINK = 0xA000000C + IO_REPARSE_TAG_DFSR = 0x80000012 + + MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16*1024 + + ############################################### + # Win32 API Bindings + ############################################### + + ffi_lib 'kernel32' + +=begin +typedef struct _FILETIME { + DWORD dwLowDateTime; + DWORD dwHighDateTime; +} FILETIME, *PFILETIME; +=end + class FILETIME < FFI::Struct + layout :dw_low_date_time, :DWORD, + :dw_high_date_time, :DWORD + end + +=begin +typedef struct _SECURITY_ATTRIBUTES { + DWORD nLength; + LPVOID lpSecurityDescriptor; + BOOL bInheritHandle; +} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; +=end + class SECURITY_ATTRIBUTES < FFI::Struct + layout :n_length, :DWORD, + :lp_security_descriptor, :LPVOID, + :b_inherit_handle, :DWORD + end + +=begin +typedef struct _WIN32_FIND_DATA { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD dwReserved0; + DWORD dwReserved1; + TCHAR cFileName[MAX_PATH]; + TCHAR cAlternateFileName[14]; +} WIN32_FIND_DATA, *PWIN32_FIND_DATA, *LPWIN32_FIND_DATA; +=end + class WIN32_FIND_DATA < FFI::Struct + layout :dw_file_attributes, :DWORD, + :ft_creation_time, FILETIME, + :ft_last_access_time, FILETIME, + :ft_last_write_time, FILETIME, + :n_file_size_high, :DWORD, + :n_file_size_low, :DWORD, + :dw_reserved_0, :DWORD, + :dw_reserved_1, :DWORD, + :c_file_name, [:BYTE, MAX_PATH*2], + :c_alternate_file_name, [:BYTE, 14] + end + +=begin +typedef struct _BY_HANDLE_FILE_INFORMATION { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD dwVolumeSerialNumber; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD nNumberOfLinks; + DWORD nFileIndexHigh; + DWORD nFileIndexLow; +} BY_HANDLE_FILE_INFORMATION, *PBY_HANDLE_FILE_INFORMATION; +=end + class BY_HANDLE_FILE_INFORMATION < FFI::Struct + layout :dw_file_attributes, :DWORD, + :ft_creation_time, FILETIME, + :ft_last_access_time, FILETIME, + :ft_last_write_time, FILETIME, + :dw_volume_serial_number, :DWORD, + :n_file_size_high, :DWORD, + :n_file_size_low, :DWORD, + :n_number_of_links, :DWORD, + :n_file_index_high, :DWORD, + :n_file_index_low, :DWORD + end + +=begin +typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; +=end + + class REPARSE_DATA_BUFFER_SYMBOLIC_LINK < FFI::Struct + layout :SubstituteNameOffset, :ushort, + :SubstituteNameLength, :ushort, + :PrintNameOffset, :ushort, + :PrintNameLength, :ushort, + :Flags, :uint32, + :PathBuffer, :ushort + + def substitute_name + string_pointer = FFI::Pointer.new(pointer.address) + offset_of(:PathBuffer) + self[:SubstituteNameOffset] + string_pointer.read_wstring(self[:SubstituteNameLength]/2) + end + def print_name + string_pointer = FFI::Pointer.new(pointer.address) + offset_of(:PathBuffer) + self[:PrintNameOffset] + string_pointer.read_wstring(self[:PrintNameLength]/2) + end + end + class REPARSE_DATA_BUFFER_MOUNT_POINT < FFI::Struct + layout :SubstituteNameOffset, :ushort, + :SubstituteNameLength, :ushort, + :PrintNameOffset, :ushort, + :PrintNameLength, :ushort, + :PathBuffer, :ushort + + def substitute_name + string_pointer = FFI::Pointer.new(pointer.address) + offset_of(:PathBuffer) + self[:SubstituteNameOffset] + string_pointer.read_wstring(self[:SubstituteNameLength]/2) + end + def print_name + string_pointer = FFI::Pointer.new(pointer.address) + offset_of(:PathBuffer) + self[:PrintNameOffset] + string_pointer.read_wstring(self[:PrintNameLength]/2) + end + end + class REPARSE_DATA_BUFFER_GENERIC < FFI::Struct + layout :DataBuffer, :uchar + end + class REPARSE_DATA_BUFFER_UNION < FFI::Union + layout :SymbolicLinkReparseBuffer, REPARSE_DATA_BUFFER_SYMBOLIC_LINK, + :MountPointReparseBuffer, REPARSE_DATA_BUFFER_MOUNT_POINT, + :GenericReparseBuffer, REPARSE_DATA_BUFFER_GENERIC + end + class REPARSE_DATA_BUFFER < FFI::Struct + layout :ReparseTag, :uint32, + :ReparseDataLength, :ushort, + :Reserved, :ushort, + :ReparseBuffer, REPARSE_DATA_BUFFER_UNION + + def reparse_buffer + if self[:ReparseTag] == IO_REPARSE_TAG_SYMLINK + self[:ReparseBuffer][:SymbolicLinkReparseBuffer] + elsif self[:ReparseTag] == IO_REPARSE_TAG_MOUNT_POINT + self[:ReparseBuffer][:MountPointReparseBuffer] + else + self[:ReparseBuffer][:GenericReparseBuffer] + end + end + end + +=begin +HANDLE WINAPI CreateFile( + __in LPCTSTR lpFileName, + __in DWORD dwDesiredAccess, + __in DWORD dwShareMode, + __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes, + __in DWORD dwCreationDisposition, + __in DWORD dwFlagsAndAttributes, + __in_opt HANDLE hTemplateFile +); +=end + safe_attach_function :CreateFileW, [:LPCTSTR, :DWORD, :DWORD, :LPSECURITY_ATTRIBUTES, :DWORD, :DWORD, :pointer], :HANDLE + +=begin +BOOL WINAPI FindClose( + __inout HANDLE hFindFile +); +=end + safe_attach_function :FindClose, [:HANDLE], :BOOL + +=begin +DWORD WINAPI GetFileAttributes( + __in LPCTSTR lpFileName +); +=end + safe_attach_function :GetFileAttributesW, [:LPCWSTR], :DWORD + +=begin +DWORD WINAPI GetFinalPathNameByHandle( + __in HANDLE hFile, + __out LPTSTR lpszFilePath, + __in DWORD cchFilePath, + __in DWORD dwFlags +); +=end + safe_attach_function :GetFinalPathNameByHandleW, [:HANDLE, :LPTSTR, :DWORD, :DWORD], :DWORD + +=begin +BOOL WINAPI GetFileInformationByHandle( + __in HANDLE hFile, + __out LPBY_HANDLE_FILE_INFORMATION lpFileInformation +); +=end + safe_attach_function :GetFileInformationByHandle, [:HANDLE, :LPBY_HANDLE_FILE_INFORMATION], :BOOL + +=begin +HANDLE WINAPI FindFirstFile( + __in LPCTSTR lpFileName, + __out LPWIN32_FIND_DATA lpFindFileData +); +=end + safe_attach_function :FindFirstFileW, [:LPCTSTR, :LPWIN32_FIND_DATA], :HANDLE + +=begin +BOOL WINAPI CreateHardLink( + __in LPCTSTR lpFileName, + __in LPCTSTR lpExistingFileName, + __reserved LPSECURITY_ATTRIBUTES lpSecurityAttributes +); +=end + safe_attach_function :CreateHardLinkW, [:LPCTSTR, :LPCTSTR, :LPSECURITY_ATTRIBUTES], :BOOLEAN + +=begin +BOOLEAN WINAPI CreateSymbolicLink( + __in LPTSTR lpSymlinkFileName, + __in LPTSTR lpTargetFileName, + __in DWORD dwFlags +); +=end + safe_attach_function :CreateSymbolicLinkW, [:LPTSTR, :LPTSTR, :DWORD], :BOOLEAN + +=begin +DWORD WINAPI GetLongPathName( + __in LPCTSTR lpszShortPath, + __out LPTSTR lpszLongPath, + __in DWORD cchBuffer +); +=end + safe_attach_function :GetLongPathNameW, [:LPCTSTR, :LPTSTR, :DWORD], :DWORD + +=begin +DWORD WINAPI GetShortPathName( + __in LPCTSTR lpszLongPath, + __out LPTSTR lpszShortPath, + __in DWORD cchBuffer +); +=end + safe_attach_function :GetShortPathNameW, [:LPCTSTR, :LPTSTR, :DWORD], :DWORD + +=begin +BOOL WINAPI DeviceIoControl( + __in HANDLE hDevice, + __in DWORD dwIoControlCode, + __in_opt LPVOID lpInBuffer, + __in DWORD nInBufferSize, + __out_opt LPVOID lpOutBuffer, + __in DWORD nOutBufferSize, + __out_opt LPDWORD lpBytesReturned, + __inout_opt LPOVERLAPPED lpOverlapped +); +=end + safe_attach_function :DeviceIoControl, [:HANDLE, :DWORD, :LPVOID, :DWORD, :LPVOID, :DWORD, :LPDWORD, :pointer], :BOOL + + ############################################### + # Helpers + ############################################### + + # takes the given path pre-pends "\\?\" and + # UTF-16LE encodes it. Used to prepare paths + # to be passed to the *W vesion of WinAPI File + # functions + def encode_path(path) + path.gsub!(::File::SEPARATOR, ::File::ALT_SEPARATOR) + (path_prepender << path).to_wstring + end + + def path_prepender + "\\\\?\\" + end + + # retrieves a file search handle and passes it + # to +&block+ along with the find_data. also + # ensures the handle is closed on exit of the block + def file_search_handle(path, &block) + begin + path = encode_path(path) + find_data = WIN32_FIND_DATA.new + handle = FindFirstFileW(path, find_data) + if handle == INVALID_HANDLE_VALUE + Chef::ReservedNames::Win32::Error.raise! + end + block.call(handle, find_data) + ensure + FindClose(handle) if handle && handle != INVALID_HANDLE_VALUE + end + end + + # retrieves a file handle and passes it + # to +&block+ along with the find_data. also + # ensures the handle is closed on exit of the block + def file_handle(path, &block) + begin + path = encode_path(path) + handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, + nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, nil) + + if handle == INVALID_HANDLE_VALUE + Chef::ReservedNames::Win32::Error.raise! + end + block.call(handle) + ensure + CloseHandle(handle) if handle && handle != INVALID_HANDLE_VALUE + end + end + + def symlink_file_handle(path, &block) + begin + path = encode_path(path) + handle = CreateFileW(path, FILE_READ_EA, FILE_SHARE_READ, + nil, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nil) + + if handle == INVALID_HANDLE_VALUE + Chef::ReservedNames::Win32::Error.raise! + end + block.call(handle) + ensure + CloseHandle(handle) if handle && handle != INVALID_HANDLE_VALUE + end + end + + def retrieve_file_info(file_name) + file_information = nil + file_handle(file_name) do |handle| + file_information = BY_HANDLE_FILE_INFORMATION.new + success = GetFileInformationByHandle(handle, file_information) + if success == 0 + Chef::ReservedNames::Win32::Error.raise! + end + end + file_information + end + + end + end + end +end diff --git a/lib/chef/win32/api/memory.rb b/lib/chef/win32/api/memory.rb new file mode 100644 index 0000000000..abd1191718 --- /dev/null +++ b/lib/chef/win32/api/memory.rb @@ -0,0 +1,105 @@ +# +# Author:: John Keiser () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/api' + +class Chef + module ReservedNames::Win32 + module API + module Memory + extend Chef::ReservedNames::Win32::API + + ############################################### + # Win32 API Constants + ############################################### + + LMEM_FIXED = 0x0000 + LMEM_MOVEABLE = 0x0002 + LMEM_NOCOMPACT = 0x0010 + LMEM_NODISCARD = 0x0020 + LMEM_ZEROINIT = 0x0040 + LMEM_MODIFY = 0x0080 + LMEM_DISCARDABLE = 0x0F00 + LMEM_VALID_FLAGS = 0x0F72 + LMEM_INVALID_HANDLE = 0x8000 + LHND = LMEM_MOVEABLE | LMEM_ZEROINIT + LPTR = LMEM_FIXED | LMEM_ZEROINIT + NONZEROLHND = LMEM_MOVEABLE + NONZEROLPTR = LMEM_FIXED + LMEM_DISCARDED = 0x4000 + LMEM_LOCKCOUNT = 0x00FF + + ############################################### + # Win32 API Bindings + ############################################### + + ffi_lib 'kernel32' + +=begin +HLOCAL WINAPI LocalAlloc( + __in UINT uFlags, + __in SIZE_T uBytes +); +=end + safe_attach_function :LocalAlloc, [ :UINT, :SIZE_T ], :pointer + +=begin +UINT WINAPI LocalFlags( + __in HLOCAL hMem +); +=end + safe_attach_function :LocalFlags, [ :pointer ], :UINT + +=begin +HLOCAL WINAPI LocalFree( + __in HLOCAL hMem +); +=end + safe_attach_function :LocalFree, [ :pointer ], :pointer + +=begin +HLOCAL WINAPI LocalReAlloc( + __in HLOCAL hMem, + __in SIZE_T uBytes, + __in UINT uFlags +); +=end + safe_attach_function :LocalReAlloc, [ :pointer, :SIZE_T, :UINT ], :pointer + +=begin +UINT WINAPI LocalSize( + __in HLOCAL hMem +); +=end + safe_attach_function :LocalSize, [ :pointer ], :SIZE_T + + ############################################### + # FFI API Bindings + ############################################### + + ffi_lib FFI::Library::LIBC + safe_attach_function :malloc, [:size_t], :pointer + safe_attach_function :calloc, [:size_t], :pointer + safe_attach_function :realloc, [:pointer, :size_t], :pointer + safe_attach_function :free, [:pointer], :void + safe_attach_function :memcpy, [:pointer, :pointer, :size_t], :pointer + + end + end + end +end diff --git a/lib/chef/win32/api/process.rb b/lib/chef/win32/api/process.rb new file mode 100644 index 0000000000..d18ad411b4 --- /dev/null +++ b/lib/chef/win32/api/process.rb @@ -0,0 +1,40 @@ +# +# Author:: John Keiser () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/api' + +class Chef + module ReservedNames::Win32 + module API + module Process + extend Chef::ReservedNames::Win32::API + + ############################################### + # Win32 API Bindings + ############################################### + + ffi_lib 'kernel32' + + safe_attach_function :GetCurrentProcess, [], :HANDLE + safe_attach_function :GetProcessHandleCount, [ :HANDLE, :LPDWORD ], :BOOL + safe_attach_function :GetProcessId, [ :HANDLE ], :DWORD + + end + end + end +end diff --git a/lib/chef/win32/api/psapi.rb b/lib/chef/win32/api/psapi.rb new file mode 100644 index 0000000000..3a5df3f179 --- /dev/null +++ b/lib/chef/win32/api/psapi.rb @@ -0,0 +1,51 @@ +# +# Author:: Seth Chisamore () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/api' + +class Chef + module ReservedNames::Win32 + module API + module PSAPI + extend Chef::ReservedNames::Win32::API + + ############################################### + # Win32 API Bindings + ############################################### + + class PROCESS_MEMORY_COUNTERS < FFI::Struct + layout :cb, :DWORD, + :PageFaultCount, :DWORD, + :PeakWorkingSetSize, :SIZE_T, + :WorkingSetSize, :SIZE_T, + :QuotaPeakPagedPoolUsage, :SIZE_T, + :QuotaPagedPoolUsage, :SIZE_T, + :QuotaPeakNonPagedPoolUsage, :SIZE_T, + :QuotaNonPagedPoolUsage, :SIZE_T, + :PagefileUsage, :SIZE_T, + :PeakPagefileUsage, :SIZE_T + end + + ffi_lib 'psapi' + + safe_attach_function :GetProcessMemoryInfo, [ :HANDLE, :pointer, :DWORD ], :BOOL + + end + end + end +end diff --git a/lib/chef/win32/api/security.rb b/lib/chef/win32/api/security.rb new file mode 100644 index 0000000000..a096b40140 --- /dev/null +++ b/lib/chef/win32/api/security.rb @@ -0,0 +1,341 @@ +# +# Author:: John Keiser () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/api' + +class Chef + module ReservedNames::Win32 + module API + module Security + extend Chef::ReservedNames::Win32::API + + ############################################### + # Win32 API Constants + ############################################### + + # ACE_HEADER AceType + ACCESS_MIN_MS_ACE_TYPE = 0x0 + ACCESS_ALLOWED_ACE_TYPE = 0x0 + ACCESS_DENIED_ACE_TYPE = 0x1 + SYSTEM_AUDIT_ACE_TYPE = 0x2 + SYSTEM_ALARM_ACE_TYPE = 0x3 + ACCESS_MAX_MS_V2_ACE_TYPE = 0x3 + ACCESS_ALLOWED_COMPOUND_ACE_TYPE = 0x4 + ACCESS_MAX_MS_V3_ACE_TYPE = 0x4 + ACCESS_MIN_MS_OBJECT_ACE_TYPE = 0x5 + ACCESS_ALLOWED_OBJECT_ACE_TYPE = 0x5 + ACCESS_DENIED_OBJECT_ACE_TYPE = 0x6 + SYSTEM_AUDIT_OBJECT_ACE_TYPE = 0x7 + SYSTEM_ALARM_OBJECT_ACE_TYPE = 0x8 + ACCESS_MAX_MS_OBJECT_ACE_TYPE = 0x8 + ACCESS_MAX_MS_V4_ACE_TYPE = 0x8 + ACCESS_MAX_MS_ACE_TYPE = 0x8 + ACCESS_ALLOWED_CALLBACK_ACE_TYPE = 0x9 + ACCESS_DENIED_CALLBACK_ACE_TYPE = 0xA + ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE = 0xB + ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE = 0xC + SYSTEM_AUDIT_CALLBACK_ACE_TYPE = 0xD + SYSTEM_ALARM_CALLBACK_ACE_TYPE = 0xE + SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE = 0xF + SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE = 0x10 + SYSTEM_MANDATORY_LABEL_ACE_TYPE = 0x11 + ACCESS_MAX_MS_V5_ACE_TYPE = 0x11 + + # ACE_HEADER AceFlags + OBJECT_INHERIT_ACE = 0x1 + CONTAINER_INHERIT_ACE = 0x2 + NO_PROPAGATE_INHERIT_ACE = 0x4 + INHERIT_ONLY_ACE = 0x8 + INHERITED_ACE = 0x10 + VALID_INHERIT_FLAGS = 0x1F + SUCCESSFUL_ACCESS_ACE_FLAG = 0x40 + FAILED_ACCESS_ACE_FLAG = 0x80 + + # SECURITY_INFORMATION flags (DWORD) + OWNER_SECURITY_INFORMATION = 0x01 + GROUP_SECURITY_INFORMATION = 0x02 + DACL_SECURITY_INFORMATION = 0x04 + SACL_SECURITY_INFORMATION = 0x08 + LABEL_SECURITY_INFORMATION = 0x10 + UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000 + UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000 + PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000 + PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000 + + # SECURITY_DESCRIPTOR_REVISION + SECURITY_DESCRIPTOR_REVISION = 1 + SECURITY_DESCRIPTOR_REVISION1 = 1 + + # SECURITY_DESCRIPTOR_CONTROL + SE_OWNER_DEFAULTED = 0x0001 + SE_GROUP_DEFAULTED = 0x0002 + SE_DACL_PRESENT = 0x0004 + SE_DACL_DEFAULTED = 0x0008 + SE_SACL_PRESENT = 0x0010 + SE_SACL_DEFAULTED = 0x0020 + SE_DACL_AUTO_INHERIT_REQ = 0x0100 + SE_SACL_AUTO_INHERIT_REQ = 0x0200 + SE_DACL_AUTO_INHERITED = 0x0400 + SE_SACL_AUTO_INHERITED = 0x0800 + SE_DACL_PROTECTED = 0x1000 + SE_SACL_PROTECTED = 0x2000 + SE_RM_CONTROL_VALID = 0x4000 + SE_SELF_RELATIVE = 0x8000 + + # ACCESS_RIGHTS_MASK + # Generic Access Rights + GENERIC_READ = 0x80000000 + GENERIC_WRITE = 0x40000000 + GENERIC_EXECUTE = 0x20000000 + GENERIC_ALL = 0x10000000 + # Standard Access Rights + DELETE = 0x00010000 + READ_CONTROL = 0x00020000 + WRITE_DAC = 0x00040000 + WRITE_OWNER = 0x00080000 + SYNCHRONIZE = 0x00100000 + STANDARD_RIGHTS_REQUIRED = 0x000F0000 + STANDARD_RIGHTS_READ = READ_CONTROL + STANDARD_RIGHTS_WRITE = READ_CONTROL + STANDARD_RIGHTS_EXECUTE = READ_CONTROL + STANDARD_RIGHTS_ALL = 0x001F0000 + SPECIFIC_RIGHTS_ALL = 0x0000FFFF + # Access System Security Right + ACCESS_SYSTEM_SECURITY = 0x01000000 + # File/Directory Specific Rights + FILE_READ_DATA = 0x0001 + FILE_LIST_DIRECTORY = 0x0001 + FILE_WRITE_DATA = 0x0002 + FILE_ADD_FILE = 0x0002 + FILE_APPEND_DATA = 0x0004 + FILE_ADD_SUBDIRECTORY = 0x0004 + FILE_CREATE_PIPE_INSTANCE = 0x0004 + FILE_READ_EA = 0x0008 + FILE_WRITE_EA = 0x0010 + FILE_EXECUTE = 0x0020 + FILE_TRAVERSE = 0x0020 + FILE_DELETE_CHILD = 0x0040 + FILE_READ_ATTRIBUTES = 0x0080 + FILE_WRITE_ATTRIBUTES = 0x0100 + FILE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | + SYNCHRONIZE | + 0x1FF + FILE_GENERIC_READ = STANDARD_RIGHTS_READ | + FILE_READ_DATA | + FILE_READ_ATTRIBUTES | + FILE_READ_EA | + SYNCHRONIZE + FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE | + FILE_WRITE_DATA | + FILE_WRITE_ATTRIBUTES | + FILE_WRITE_EA | + FILE_APPEND_DATA | + SYNCHRONIZE + FILE_GENERIC_EXECUTE = STANDARD_RIGHTS_EXECUTE | + FILE_READ_ATTRIBUTES | + FILE_EXECUTE | + SYNCHRONIZE + # Access Token Rights (for OpenProcessToken) + # Access Rights for Access-Token Objects (used in OpenProcessToken) + TOKEN_ASSIGN_PRIMARY = 0x0001 + TOKEN_DUPLICATE = 0x0002 + TOKEN_IMPERSONATE = 0x0004 + TOKEN_QUERY = 0x0008 + TOKEN_QUERY_SOURCE = 0x0010 + TOKEN_ADJUST_PRIVILEGES = 0x0020 + TOKEN_ADJUST_GROUPS = 0x0040 + TOKEN_ADJUST_DEFAULT = 0x0080 + TOKEN_ADJUST_SESSIONID = 0x0100 + TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY) + TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | + TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | + TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT | + TOKEN_ADJUST_SESSIONID) + + # AdjustTokenPrivileges + SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001 + SE_PRIVILEGE_ENABLED = 0x00000002 + SE_PRIVILEGE_REMOVED = 0X00000004 + SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000 + SE_PRIVILEGE_VALID_ATTRIBUTES = SE_PRIVILEGE_ENABLED_BY_DEFAULT | + SE_PRIVILEGE_ENABLED | + SE_PRIVILEGE_REMOVED | + SE_PRIVILEGE_USED_FOR_ACCESS + + # Minimum size of a SECURITY_DESCRIPTOR. TODO: this is probably platform dependent. + # Make it work on 64 bit. + SECURITY_DESCRIPTOR_MIN_LENGTH = 20 + + # ACL revisions + ACL_REVISION = 2 + ACL_REVISION_DS = 4 + ACL_REVISION1 = 1 + ACL_REVISION2 = 2 + ACL_REVISION3 = 3 + ACL_REVISION4 = 4 + MIN_ACL_REVISION = ACL_REVISION2 + MAX_ACL_REVISION = ACL_REVISION4 + + MAXDWORD = 0xffffffff + + ############################################### + # Win32 API Bindings + ############################################### + + SE_OBJECT_TYPE = enum :SE_OBJECT_TYPE, [ + :SE_UNKNOWN_OBJECT_TYPE, + :SE_FILE_OBJECT, + :SE_SERVICE, + :SE_PRINTER, + :SE_REGISTRY_KEY, + :SE_LMSHARE, + :SE_KERNEL_OBJECT, + :SE_WINDOW_OBJECT, + :SE_DS_OBJECT, + :SE_DS_OBJECT_ALL, + :SE_PROVIDER_DEFINED_OBJECT, + :SE_WMIGUID_OBJECT, + :SE_REGISTRY_WOW64_32KEY + ] + + SID_NAME_USE = enum :SID_NAME_USE, [ + :SidTypeUser, 1, + :SidTypeGroup, + :SidTypeDomain, + :SidTypeAlias, + :SidTypeWellKnownGroup, + :SidTypeDeletedAccount, + :SidTypeInvalid, + :SidTypeUnknown, + :SidTypeComputer, + :SidTypeLabel + ] + + # SECURITY_DESCRIPTOR is an opaque structure whose contents can vary. Pass the + # pointer around and free it with LocalFree. + # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379561(v=vs.85).aspx + + # SID is an opaque structure. Pass the pointer around. + + # ACL type is a header with some information, followed by an array of ACEs + # http://msdn.microsoft.com/en-us/library/windows/desktop/aa374931(v=VS.85).aspx + class ACLStruct < FFI::Struct + layout :AclRevision, :uchar, + :Sbzl, :uchar, + :AclSize, :ushort, + :AceCount, :ushort, + :Sbz2, :ushort + end + + class ACE_HEADER < FFI::Struct + layout :AceType, :uchar, + :AceFlags, :uchar, + :AceSize, :ushort + end + + class ACE_WITH_MASK_AND_SID < FFI::Struct + layout :AceType, :uchar, + :AceFlags, :uchar, + :AceSize, :ushort, + :Mask, :uint32, + :SidStart, :uint32 + + # The AceTypes this structure supports + def self.supports?(ace_type) + [ + ACCESS_ALLOWED_ACE_TYPE, + ACCESS_DENIED_ACE_TYPE, + SYSTEM_AUDIT_ACE_TYPE, + SYSTEM_ALARM_ACE_TYPE + ].include?(ace_type) + end + end + + class LUID < FFI::Struct + layout :LowPart, :DWORD, + :HighPart, :LONG + end + + class LUID_AND_ATTRIBUTES < FFI::Struct + layout :Luid, LUID, + :Attributes, :DWORD + end + + class TOKEN_PRIVILEGES < FFI::Struct + layout :PrivilegeCount, :DWORD, + :Privileges, LUID_AND_ATTRIBUTES + + def self.size_with_privileges(num_privileges) + offset_of(:Privileges) + LUID_AND_ATTRIBUTES.size*num_privileges + end + + def size_with_privileges + TOKEN_PRIVILEGES.size_with_privileges(self[:PrivilegeCount]) + end + + def privilege(index) + LUID_AND_ATTRIBUTES.new(pointer + offset_of(:Privileges) + (index * LUID_AND_ATTRIBUTES.size)) + end + end + + ffi_lib "advapi32" + + safe_attach_function :AddAce, [ :pointer, :DWORD, :DWORD, :LPVOID, :DWORD ], :BOOL + safe_attach_function :AddAccessAllowedAce, [ :pointer, :DWORD, :DWORD, :pointer ], :BOOL + safe_attach_function :AddAccessAllowedAceEx, [ :pointer, :DWORD, :DWORD, :DWORD, :pointer ], :BOOL + safe_attach_function :AddAccessDeniedAce, [ :pointer, :DWORD, :DWORD, :pointer ], :BOOL + safe_attach_function :AddAccessDeniedAceEx, [ :pointer, :DWORD, :DWORD, :DWORD, :pointer ], :BOOL + safe_attach_function :AdjustTokenPrivileges, [ :HANDLE, :BOOL, :pointer, :DWORD, :pointer, :PDWORD ], :BOOL + safe_attach_function :ConvertSidToStringSidA, [ :pointer, :pointer ], :BOOL + safe_attach_function :ConvertStringSidToSidW, [ :pointer, :pointer ], :BOOL + safe_attach_function :DeleteAce, [ :pointer, :DWORD ], :BOOL + safe_attach_function :EqualSid, [ :pointer, :pointer ], :BOOL + safe_attach_function :FreeSid, [ :pointer ], :pointer + safe_attach_function :GetAce, [ :pointer, :DWORD, :pointer ], :BOOL + safe_attach_function :GetLengthSid, [ :pointer ], :DWORD + safe_attach_function :GetNamedSecurityInfoW, [ :LPWSTR, :SE_OBJECT_TYPE, :DWORD, :pointer, :pointer, :pointer, :pointer, :pointer ], :DWORD + safe_attach_function :GetSecurityDescriptorControl, [ :pointer, :PWORD, :LPDWORD], :BOOL + safe_attach_function :GetSecurityDescriptorDacl, [ :pointer, :LPBOOL, :pointer, :LPBOOL ], :BOOL + safe_attach_function :GetSecurityDescriptorGroup, [ :pointer, :pointer, :LPBOOL], :BOOL + safe_attach_function :GetSecurityDescriptorOwner, [ :pointer, :pointer, :LPBOOL], :BOOL + safe_attach_function :GetSecurityDescriptorSacl, [ :pointer, :LPBOOL, :pointer, :LPBOOL ], :BOOL + safe_attach_function :InitializeAcl, [ :pointer, :DWORD, :DWORD ], :BOOL + safe_attach_function :InitializeSecurityDescriptor, [ :pointer, :DWORD ], :BOOL + safe_attach_function :IsValidAcl, [ :pointer ], :BOOL + safe_attach_function :IsValidSecurityDescriptor, [ :pointer ], :BOOL + safe_attach_function :IsValidSid, [ :pointer ], :BOOL + safe_attach_function :LookupAccountNameW, [ :LPCWSTR, :LPCWSTR, :pointer, :LPDWORD, :LPWSTR, :LPDWORD, :pointer ], :BOOL + safe_attach_function :LookupAccountSidW, [ :LPCWSTR, :pointer, :LPWSTR, :LPDWORD, :LPWSTR, :LPDWORD, :pointer ], :BOOL + safe_attach_function :LookupPrivilegeNameW, [ :LPCWSTR, :PLUID, :LPWSTR, :LPDWORD ], :BOOL + safe_attach_function :LookupPrivilegeDisplayNameW, [ :LPCWSTR, :LPCWSTR, :LPWSTR, :LPDWORD, :LPDWORD ], :BOOL + safe_attach_function :LookupPrivilegeValueW, [ :LPCWSTR, :LPCWSTR, :PLUID ], :BOOL + safe_attach_function :MakeAbsoluteSD, [ :pointer, :pointer, :LPDWORD, :pointer, :LPDWORD, :pointer, :LPDWORD, :pointer, :LPDWORD, :pointer, :LPDWORD], :BOOL + safe_attach_function :OpenProcessToken, [ :HANDLE, :DWORD, :PHANDLE ], :BOOL + safe_attach_function :QuerySecurityAccessMask, [ :DWORD, :LPDWORD ], :void + safe_attach_function :SetFileSecurityW, [ :LPWSTR, :DWORD, :pointer ], :BOOL + safe_attach_function :SetNamedSecurityInfoW, [ :LPWSTR, :SE_OBJECT_TYPE, :DWORD, :pointer, :pointer, :pointer, :pointer ], :DWORD + safe_attach_function :SetSecurityAccessMask, [ :DWORD, :LPDWORD ], :void + safe_attach_function :SetSecurityDescriptorDacl, [ :pointer, :BOOL, :pointer, :BOOL ], :BOOL + safe_attach_function :SetSecurityDescriptorGroup, [ :pointer, :pointer, :BOOL ], :BOOL + safe_attach_function :SetSecurityDescriptorOwner, [ :pointer, :pointer, :BOOL ], :BOOL + safe_attach_function :SetSecurityDescriptorSacl, [ :pointer, :BOOL, :pointer, :BOOL ], :BOOL + + end + end + end +end diff --git a/lib/chef/win32/api/system.rb b/lib/chef/win32/api/system.rb new file mode 100644 index 0000000000..60f381aa5a --- /dev/null +++ b/lib/chef/win32/api/system.rb @@ -0,0 +1,192 @@ +# +# Author:: Seth Chisamore () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/api' + +class Chef + module ReservedNames::Win32 + module API + module System + extend Chef::ReservedNames::Win32::API + + ############################################### + # Win32 API Constants + ############################################### + + # http://msdn.microsoft.com/en-us/library/ms724833(v=vs.85).aspx + + # Suite Masks + # Microsoft BackOffice components are installed. + VER_SUITE_BACKOFFICE = 0x00000004 + # Windows Server 2003, Web Edition is installed. + VER_SUITE_BLADE = 0x00000400 + # Windows Server 2003, Compute Cluster Edition is installed. + VER_SUITE_COMPUTE_SERVER = 0x00004000 + # Windows Server 2008 Datacenter, Windows Server 2003, Datacenter Edition, or Windows 2000 Datacenter Server is installed. + VER_SUITE_DATACENTER = 0x00000080 + # Windows Server 2008 Enterprise, Windows Server 2003, Enterprise Edition, or Windows 2000 Advanced Server is installed. Refer to the Remarks section for more information about this bit flag. + VER_SUITE_ENTERPRISE = 0x00000002 + # Windows XP Embedded is installed. + VER_SUITE_EMBEDDEDNT = 0x00000040 + # Windows Vista Home Premium, Windows Vista Home Basic, or Windows XP Home Edition is installed. + VER_SUITE_PERSONAL = 0x00000200 + # Remote Desktop is supported, but only one interactive session is supported. This value is set unless the system is running in application server mode. + VER_SUITE_SINGLEUSERTS = 0x00000100 + # Microsoft Small Business Server was once installed on the system, but may have been upgraded to another version of Windows. Refer to the Remarks section for more information about this bit flag. + VER_SUITE_SMALLBUSINESS = 0x00000001 + # Microsoft Small Business Server is installed with the restrictive client license in force. Refer to the Remarks section for more information about this bit flag. + VER_SUITE_SMALLBUSINESS_RESTRICTED = 0x00000020 + # Windows Storage Server 2003 R2 or Windows Storage Server 2003is installed. + VER_SUITE_STORAGE_SERVER = 0x00002000 + # Terminal Services is installed. This value is always set. + # If VER_SUITE_TERMINAL is set but VER_SUITE_SINGLEUSERTS is not set, the system is running in application server mode. + VER_SUITE_TERMINAL = 0x00000010 + # Windows Home Server is installed. + VER_SUITE_WH_SERVER = 0x00008000 + + # Product Type + # The system is a domain controller and the operating system is Windows Server 2008 R2, Windows Server 2008, Windows Server 2003, or Windows 2000 Server. + VER_NT_DOMAIN_CONTROLLER = 0x0000002 + # The operating system is Windows Server 2008 R2, Windows Server 2008, Windows Server 2003, or Windows 2000 Server. + # Note that a server that is also a domain controller is reported as VER_NT_DOMAIN_CONTROLLER, not VER_NT_SERVER. + VER_NT_SERVER = 0x0000003 + # The operating system is Windows 7, Windows Vista, Windows XP Professional, Windows XP Home Edition, or Windows 2000 Professional. + VER_NT_WORKSTATION = 0x0000001 + + # Product Info + # http://msdn.microsoft.com/en-us/library/ms724358(v=vs.85).aspx + PRODUCT_BUSINESS = 0x00000006 # Business + PRODUCT_BUSINESS_N = 0x00000010 # Business N + PRODUCT_CLUSTER_SERVER = 0x00000012 # HPC Edition + PRODUCT_DATACENTER_SERVER = 0x00000008 # Server Datacenter (full installation) + PRODUCT_DATACENTER_SERVER_CORE = 0x0000000C # Server Datacenter (core installation) + PRODUCT_DATACENTER_SERVER_CORE_V = 0x00000027 # Server Datacenter without Hyper-V (core installation) + PRODUCT_DATACENTER_SERVER_V = 0x00000025 # Server Datacenter without Hyper-V (full installation) + PRODUCT_ENTERPRISE = 0x00000004 # Enterprise + PRODUCT_ENTERPRISE_E = 0x00000046 # Not supported + PRODUCT_ENTERPRISE_N = 0x0000001B # Enterprise N + PRODUCT_ENTERPRISE_SERVER = 0x0000000A # Server Enterprise (full installation) + PRODUCT_ENTERPRISE_SERVER_CORE = 0x0000000E # Server Enterprise (core installation) + PRODUCT_ENTERPRISE_SERVER_CORE_V = 0x00000029 # Server Enterprise without Hyper-V (core installation) + PRODUCT_ENTERPRISE_SERVER_IA64 = 0x0000000F # Server Enterprise for Itanium-based Systems + PRODUCT_ENTERPRISE_SERVER_V = 0x00000026 # Server Enterprise without Hyper-V (full installation) + PRODUCT_HOME_BASIC = 0x00000002 # Home Basic + PRODUCT_HOME_BASIC_E = 0x00000043 # Not supported + PRODUCT_HOME_BASIC_N = 0x00000005 # Home Basic N + PRODUCT_HOME_PREMIUM = 0x00000003 # Home Premium + PRODUCT_HOME_PREMIUM_E = 0x00000044 # Not supported + PRODUCT_HOME_PREMIUM_N = 0x0000001A # Home Premium N + PRODUCT_HYPERV = 0x0000002A # Microsoft Hyper-V Server + PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT = 0x0000001E # Windows Essential Business Server Management Server + PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING = 0x00000020 # Windows Essential Business Server Messaging Server + PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY = 0x0000001F # Windows Essential Business Server Security Server + PRODUCT_PROFESSIONAL = 0x00000030 # Professional + PRODUCT_PROFESSIONAL_E = 0x00000045 # Not supported + PRODUCT_PROFESSIONAL_N = 0x00000031 # Professional N + PRODUCT_SERVER_FOR_SMALLBUSINESS = 0x00000018 # Windows Server 2008 for Windows Essential Server Solutions + PRODUCT_SERVER_FOR_SMALLBUSINESS_V = 0x00000023 # Windows Server 2008 without Hyper-V for Windows Essential Server Solutions + PRODUCT_SERVER_FOUNDATION = 0x00000021 # Server Foundation + PRODUCT_HOME_PREMIUM_SERVER = 0x00000022 # Windows Home Server 2011 + PRODUCT_SB_SOLUTION_SERVER = 0x00000032 # Windows Small Business Server 2011 Essentials + PRODUCT_HOME_SERVER = 0x00000013 # Windows Storage Server 2008 R2 Essentials + PRODUCT_SMALLBUSINESS_SERVER = 0x00000009 # Windows Small Business Server + PRODUCT_SOLUTION_EMBEDDEDSERVER = 0x00000038 # Windows MultiPoint Server + PRODUCT_STANDARD_SERVER = 0x00000007 # Server Standard (full installation) + PRODUCT_STANDARD_SERVER_CORE = 0x0000000D # Server Standard (core installation) + PRODUCT_STANDARD_SERVER_CORE_V = 0x00000028 # Server Standard without Hyper-V (core installation) + PRODUCT_STANDARD_SERVER_V = 0x00000024 # Server Standard without Hyper-V (full installation) + PRODUCT_STARTER = 0x0000000B # Starter + PRODUCT_STARTER_E = 0x00000042 # Not supported + PRODUCT_STARTER_N = 0x0000002F # Starter N + PRODUCT_STORAGE_ENTERPRISE_SERVER = 0x00000017 # Storage Server Enterprise + PRODUCT_STORAGE_EXPRESS_SERVER = 0x00000014 # Storage Server Express + PRODUCT_STORAGE_STANDARD_SERVER = 0x00000015 # Storage Server Standard + PRODUCT_STORAGE_WORKGROUP_SERVER = 0x00000016 # Storage Server Workgroup + PRODUCT_UNDEFINED = 0x00000000 # An unknown product + PRODUCT_ULTIMATE = 0x00000001 # Ultimate + PRODUCT_ULTIMATE_E = 0x00000047 # Not supported + PRODUCT_ULTIMATE_N = 0x0000001C # Ultimate N + PRODUCT_WEB_SERVER = 0x00000011 # Web Server (full installation) + PRODUCT_WEB_SERVER_CORE = 0x0000001D # Web Server (core installation) + + # GetSystemMetrics + # The build number if the system is Windows Server 2003 R2; otherwise, 0. + SM_SERVERR2 = 89 + + ############################################### + # Win32 API Bindings + ############################################### + + ffi_lib 'kernel32', 'user32' + + class OSVERSIONINFOEX < FFI::Struct + layout :dw_os_version_info_size, :DWORD, + :dw_major_version, :DWORD, + :dw_minor_version, :DWORD, + :dw_build_number, :DWORD, + :dw_platform_id, :DWORD, + :sz_csd_version, [:BYTE, 256], + :w_service_pack_major, :WORD, + :w_service_pack_minor, :WORD, + :w_suite_mask, :WORD, + :w_product_type, :BYTE, + :w_reserved, :BYTE + end + +=begin +BOOL WINAPI CloseHandle( + __in HANDLE hObject +); +=end + safe_attach_function :CloseHandle, [ :HANDLE ], :BOOL + +=begin +DWORD WINAPI GetVersion(void); +=end + safe_attach_function :GetVersion, [], :DWORD + +=begin +BOOL WINAPI GetVersionEx( + __inout LPOSVERSIONINFO lpVersionInfo +); +=end + safe_attach_function :GetVersionExW, [:pointer], :BOOL + safe_attach_function :GetVersionExA, [:pointer], :BOOL + +=begin +BOOL WINAPI GetProductInfo( + __in DWORD dwOSMajorVersion, + __in DWORD dwOSMinorVersion, + __in DWORD dwSpMajorVersion, + __in DWORD dwSpMinorVersion, + __out PDWORD pdwReturnedProductType +); +=end + safe_attach_function :GetProductInfo, [:DWORD, :DWORD, :DWORD, :DWORD, :PDWORD], :BOOL + +=begin +int WINAPI GetSystemMetrics( + __in int nIndex +); +=end + safe_attach_function :GetSystemMetrics, [:int], :int + + end + end + end +end diff --git a/lib/chef/win32/api/unicode.rb b/lib/chef/win32/api/unicode.rb new file mode 100644 index 0000000000..0b2cb09a6b --- /dev/null +++ b/lib/chef/win32/api/unicode.rb @@ -0,0 +1,178 @@ +# +# Author:: Seth Chisamore () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/api' + +class Chef + module ReservedNames::Win32 + module API + module Unicode + extend Chef::ReservedNames::Win32::API + + ############################################### + # Win32 API Constants + ############################################### + + CP_ACP = 0 + CP_OEMCP = 1 + CP_MACCP = 2 + CP_THREAD_ACP = 3 + CP_SYMBOL = 42 + CP_UTF7 = 65000 + CP_UTF8 = 65001 + + MB_PRECOMPOSED = 0x00000001 + MB_COMPOSITE = 0x00000002 + MB_USEGLYPHCHARS = 0x00000004 + MB_ERR_INVALID_CHARS = 0x00000008 + + WC_COMPOSITECHECK = 0x00000200 + WC_DISCARDNS = 0x00000010 + WC_SEPCHARS = 0x00000020 + WC_DEFAULTCHAR = 0x00000040 + WC_NO_BEST_FIT_CHARS = 0x00000400 + + ANSI_CHARSET = 0 + DEFAULT_CHARSET = 1 + SYMBOL_CHARSET = 2 + SHIFTJIS_CHARSET = 128 + HANGEUL_CHARSET = 129 + HANGUL_CHARSET = 129 + GB2312_CHARSET = 134 + CHINESEBIG5_CHARSET = 136 + OEM_CHARSET = 255 + JOHAB_CHARSET = 130 + HEBREW_CHARSET = 177 + ARABIC_CHARSET = 178 + GREEK_CHARSET = 161 + TURKISH_CHARSET = 162 + VIETNAMESE_CHARSET = 163 + THAI_CHARSET = 222 + EASTEUROPE_CHARSET = 238 + RUSSIAN_CHARSET = 204 + + IS_TEXT_UNICODE_ASCII16 = 0x0001 + IS_TEXT_UNICODE_REVERSE_ASCII16 = 0x0010 + IS_TEXT_UNICODE_STATISTICS = 0x0002 + IS_TEXT_UNICODE_REVERSE_STATISTICS = 0x0020 + IS_TEXT_UNICODE_CONTROLS = 0x0004 + IS_TEXT_UNICODE_REVERSE_CONTROLS = 0x0040 + IS_TEXT_UNICODE_SIGNATURE = 0x0008 + IS_TEXT_UNICODE_REVERSE_SIGNATURE = 0x0080 + IS_TEXT_UNICODE_ILLEGAL_CHARS = 0x0100 + IS_TEXT_UNICODE_ODD_LENGTH = 0x0200 + IS_TEXT_UNICODE_DBCS_LEADBYTE = 0x0400 + IS_TEXT_UNICODE_NULL_BYTES = 0x1000 + IS_TEXT_UNICODE_UNICODE_MASK = 0x000F + IS_TEXT_UNICODE_REVERSE_MASK = 0x00F0 + IS_TEXT_UNICODE_NOT_UNICODE_MASK = 0x0F00 + IS_TEXT_UNICODE_NOT_ASCII_MASK = 0xF000 + + TCI_SRCCHARSET = 1 + TCI_SRCCODEPAGE = 2 + TCI_SRCFONTSIG = 3 + TCI_SRCLOCALE = 0x100 + + ############################################### + # Win32 API Bindings + ############################################### + + ffi_lib 'kernel32', 'advapi32' + +=begin +BOOL IsTextUnicode( + __in const VOID *lpv, + __in int iSize, + __inout LPINT lpiResult +); +=end + safe_attach_function :IsTextUnicode, [:pointer, :int, :LPINT], :BOOL + +=begin +int MultiByteToWideChar( + __in UINT CodePage, + __in DWORD dwFlags, + __in LPCSTR lpMultiByteStr, + __in int cbMultiByte, + __out LPWSTR lpWideCharStr, + __in int cchWideChar +); +=end + safe_attach_function :MultiByteToWideChar, [:UINT, :DWORD, :LPCSTR, :int, :LPWSTR, :int], :int + +=begin +int WideCharToMultiByte( + __in UINT CodePage, + __in DWORD dwFlags, + __in LPCWSTR lpWideCharStr, + __in int cchWideChar, + __out LPSTR lpMultiByteStr, + __in int cbMultiByte, + __in LPCSTR lpDefaultChar, + __out LPBOOL lpUsedDefaultChar +); +=end + safe_attach_function :WideCharToMultiByte, [:UINT, :DWORD, :LPCWSTR, :int, :LPSTR, :int, :LPCSTR, :LPBOOL], :int + + ############################################### + # Helpers + ############################################### + + def utf8_to_wide(ustring) + # ensure it is actually UTF-8 + # Ruby likes to mark binary data as ASCII-8BIT + ustring = (ustring + "").force_encoding('UTF-8') if ustring.respond_to?(:force_encoding) && ustring.encoding.name != "UTF-8" + + # ensure we have the double-null termination Windows Wide likes + ustring = ustring + "\000\000" if ustring[-1].chr != "\000" + + # encode it all as UTF-16LE AKA Windows Wide Character AKA Windows Unicode + ustring = begin + if ustring.respond_to?(:encode) + ustring.encode('UTF-16LE') + else + require 'iconv' + Iconv.conv("UTF-16LE", "UTF-8", ustring) + end + end + ustring + end + + def wide_to_utf8(wstring) + # ensure it is actually UTF-16LE + # Ruby likes to mark binary data as ASCII-8BIT + wstring = wstring.force_encoding('UTF-16LE') if wstring.respond_to?(:force_encoding) + + # encode it all as UTF-8 + wstring = begin + if wstring.respond_to?(:encode) + wstring.encode('UTF-8') + else + require 'iconv' + Iconv.conv("UTF-8", "UTF-16LE", wstring) + end + end + # remove trailing CRLF and NULL characters + wstring.strip! + wstring + end + + end + end + end +end diff --git a/lib/chef/win32/error.rb b/lib/chef/win32/error.rb new file mode 100644 index 0000000000..716ca99d01 --- /dev/null +++ b/lib/chef/win32/error.rb @@ -0,0 +1,73 @@ +# +# Author:: John Keiser () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/api/error' +require 'chef/win32/memory' +require 'chef/win32/unicode' +require 'chef/exceptions' + +class Chef + module ReservedNames::Win32 + class Error + include Chef::ReservedNames::Win32::API::Error + extend Chef::ReservedNames::Win32::API::Error + + def self.format_message(message_id = 0, args = {}) + flags = args[:flags] || FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY + source = args[:source] + language_id = args[:language_id] || 0 + varargs = args[:varargs] || [:int, 0] + buffer = FFI::MemoryPointer.new :pointer + num_chars = FormatMessageW(flags | FORMAT_MESSAGE_ALLOCATE_BUFFER, source, message_id, language_id, buffer, 0, *varargs) + if num_chars == 0 + raise! + end + + # Extract the string + begin + return buffer.read_pointer.read_wstring(num_chars) + ensure + Chef::ReservedNames::Win32::Memory.local_free(buffer.read_pointer) + end + end + + def self.get_last_error + GetLastError() + end + + # Raises the last error. This should only be called by + # Win32 API wrapper functions, and then only when wrapped + # in an if() statement (since it unconditionally exits) + # === Returns + # nil::: always returns nil when it does not raise + # === Raises + # Chef::Exceptions::Win32APIError::: + def self.raise!(message = nil) + code = get_last_error + msg = format_message(code).strip + formatted_message = "" + formatted_message << message if message + formatted_message << "---- Begin Win32 API output ----\n" + formatted_message << "System Error Code: #{code}\n" + formatted_message << "System Error Message: #{msg}\n" + formatted_message << "---- End Win32 API output ----\n" + raise Chef::Exceptions::Win32APIError, msg + "\n" + formatted_message + end + end + end +end diff --git a/lib/chef/win32/file.rb b/lib/chef/win32/file.rb new file mode 100644 index 0000000000..d489c9ce8a --- /dev/null +++ b/lib/chef/win32/file.rb @@ -0,0 +1,167 @@ +# +# Author:: Seth Chisamore () +# Author:: Mark Mzyk () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/api/file' +require 'chef/win32/api/security' +require 'chef/win32/error' + +class Chef + module ReservedNames::Win32 + class File + include Chef::ReservedNames::Win32::API::File + extend Chef::ReservedNames::Win32::API::File + + # Creates a symbolic link called +new_name+ for the file or directory + # +old_name+. + # + # This method requires Windows Vista or later to work. Otherwise, it + # returns nil as per MRI. + # + def self.link(old_name, new_name) + raise Errno::ENOENT, "(#{old_name}, #{new_name})" unless ::File.exist?(old_name) + # TODO do a check for CreateHardLinkW and + # raise NotImplemented exception on older Windows + old_name = encode_path(old_name) + new_name = encode_path(new_name) + unless CreateHardLinkW(new_name, old_name, nil) + Chef::ReservedNames::Win32::Error.raise! + end + end + + # Creates a symbolic link called +new_name+ for the file or directory + # +old_name+. + # + # This method requires Windows Vista or later to work. Otherwise, it + # returns nil as per MRI. + # + def self.symlink(old_name, new_name) + # raise Errno::ENOENT, "(#{old_name}, #{new_name})" unless ::File.exist?(old_name) + # TODO do a check for CreateSymbolicLinkW and + # raise NotImplemented exception on older Windows + flags = ::File.directory?(old_name) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0 + old_name = encode_path(old_name) + new_name = encode_path(new_name) + unless CreateSymbolicLinkW(new_name, old_name, flags) + Chef::ReservedNames::Win32::Error.raise! + end + end + + # Return true if the named file is a symbolic link, false otherwise. + # + # This method requires Windows Vista or later to work. Otherwise, it + # always returns false as per MRI. + # + def self.symlink?(file_name) + is_symlink = false + path = encode_path(file_name) + if ::File.exists?(file_name) + if ((GetFileAttributesW(path) & FILE_ATTRIBUTE_REPARSE_POINT) > 0) + file_search_handle(file_name) do |handle, find_data| + if find_data[:dw_reserved_0] == IO_REPARSE_TAG_SYMLINK + is_symlink = true + end + end + end + end + is_symlink + end + + # Returns the path of the of the symbolic link referred to by +file+. + # + # Requires Windows Vista or later. On older versions of Windows it + # will raise a NotImplementedError, as per MRI. + # + def self.readlink(link_name) + raise Errno::ENOENT, link_name unless ::File.exists?(link_name) + symlink_file_handle(link_name) do |handle| + # Go to DeviceIoControl to get the symlink information + # http://msdn.microsoft.com/en-us/library/windows/desktop/aa364571(v=vs.85).aspx + reparse_buffer = FFI::MemoryPointer.new(MAXIMUM_REPARSE_DATA_BUFFER_SIZE) + parsed_size = FFI::Buffer.new(:long).write_long(0) + if DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, nil, 0, reparse_buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, parsed_size, nil) == 0 + Chef::ReservedNames::Win32::Error.raise! + end + + # Ensure it's a symbolic link + reparse_buffer = REPARSE_DATA_BUFFER.new(reparse_buffer) + if reparse_buffer[:ReparseTag] != IO_REPARSE_TAG_SYMLINK + raise Errno::EACCES, "#{link_name} is not a symlink" + end + + # Return the link destination (strip off \??\ at the beginning, which is a local filesystem thing) + link_dest = reparse_buffer.reparse_buffer.substitute_name + if link_dest =~ /^\\\?\?\\/ + link_dest = link_dest[4..-1] + end + link_dest + end + end + + # Gets the short form of a path (Administrator -> ADMINI~1) + def self.get_short_path_name(path) + path = path.to_wstring + size = GetShortPathNameW(path, nil, 0) + if size == 0 + Chef::ReservedNames::Win32::Error.raise! + end + result = FFI::MemoryPointer.new :char, (size+1)*2 + if GetShortPathNameW(path, result, size+1) == 0 + Chef::ReservedNames::Win32::Error.raise! + end + result.read_wstring(size) + end + + # Gets the long form of a path (ADMINI~1 -> Administrator) + def self.get_long_path_name(path) + path = path.to_wstring + size = GetLongPathNameW(path, nil, 0) + if size == 0 + Chef::ReservedNames::Win32::Error.raise! + end + result = FFI::MemoryPointer.new :char, (size+1)*2 + if GetLongPathNameW(path, result, size+1) == 0 + Chef::ReservedNames::Win32::Error.raise! + end + result.read_wstring(size) + end + + def self.info(file_name) + Info.new(file_name) + end + + def self.verify_links_supported! + begin + CreateSymbolicLinkW(nil) + rescue Chef::Exceptions::Win32APIFunctionNotImplemented => e + raise e + rescue Exception + # things are ok. + end + end + + # ::File compat + class << self + alias :stat :info + end + + end + end +end + +require 'chef/win32/file/info' diff --git a/lib/chef/win32/file/info.rb b/lib/chef/win32/file/info.rb new file mode 100644 index 0000000000..0f07428106 --- /dev/null +++ b/lib/chef/win32/file/info.rb @@ -0,0 +1,100 @@ +# +# Author:: Seth Chisamore () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/file' + +class Chef + module ReservedNames::Win32 + class File + + # Objects of class Chef::ReservedNames::Win32::File::Stat encapsulate common status + # information for Chef::ReservedNames::Win32::File objects. The information + # is recorded at the moment the Chef::ReservedNames::Win32::File::Stat object is + # created; changes made to the file after that point will not be reflected. + class Info + + include Chef::ReservedNames::Win32::API::File + include Chef::ReservedNames::Win32::API + + # http://msdn.microsoft.com/en-us/library/windows/desktop/aa363788(v=vs.85).aspx + def initialize(file_name) + raise Errno::ENOENT, file_name unless ::File.exist?(file_name) + @file_info = retrieve_file_info(file_name) + end + + def volume_serial_number + @file_info[:dw_volume_serial_number] + end + + def index + make_uint64(@file_info[:n_file_index_low], @file_info[:n_file_index_high]) + end + + def last_access_time + parse_time(@file_info[:ft_last_access_time]) + end + + def creation_time + parse_time(@file_info[:ft_creation_time]) + end + + def last_write_time + parse_time(@file_info[:ft_last_write_time]) + end + + def links + @file_info[:n_number_of_links] + end + + def size + make_uint64(@file_info[:n_file_size_low], @file_info[:n_file_size_high]) + end + + ############################## + # ::File::Stat compat + alias :atime :last_access_time + alias :mtime :last_write_time + alias :ctime :creation_time + + # we're faking it here, but this is in the spirit of ino in *nix + # + # from MSDN: + # + # "The identifier (low and high parts) and the volume serial number + # uniquely identify a file on a single computer. To determine whether + # two open handles represent the same file, combine the identifier + # and the volume serial number for each file and compare them."" + # + def ino + volume_serial_number + index + end + ############################## + + # given a +Chef::ReservedNames::Win32::API::File::FILETIME+ structure convert into a + # Ruby +Time+ object. + # + def parse_time(file_time_struct) + wtime_to_time(make_uint64(file_time_struct[:dw_low_date_time], + file_time_struct[:dw_high_date_time])) + end + + + end + end + end +end diff --git a/lib/chef/win32/handle.rb b/lib/chef/win32/handle.rb new file mode 100644 index 0000000000..60e35916ad --- /dev/null +++ b/lib/chef/win32/handle.rb @@ -0,0 +1,48 @@ +# +# Author:: John Keiser () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/api/process' +require 'chef/win32/api/psapi' +require 'chef/win32/api/system' +require 'chef/win32/error' + +class Chef + module ReservedNames::Win32 + class Handle + extend Chef::ReservedNames::Win32::API::Process + + def initialize(handle) + @handle = handle + ObjectSpace.define_finalizer(self, Handle.close_handle_finalizer(handle)) + end + + attr_reader :handle + + def self.close_handle_finalizer(handle) + proc { close_handle(handle) } + end + + def self.close_handle(handle) + unless CloseHandle(handle) + Chef::ReservedNames::Win32::Error.raise! + end + end + + end + end +end diff --git a/lib/chef/win32/memory.rb b/lib/chef/win32/memory.rb new file mode 100644 index 0000000000..8a61d27ef0 --- /dev/null +++ b/lib/chef/win32/memory.rb @@ -0,0 +1,101 @@ +# +# Author:: John Keiser () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/error' +require 'chef/win32/api/memory' + +class Chef + module ReservedNames::Win32 + class Memory + include Chef::ReservedNames::Win32::API::Memory + extend Chef::ReservedNames::Win32::API::Memory + + # local_alloc(length[, flags]) [BLOCK] + # Allocates memory using LocalAlloc + # If BLOCK is specified, the memory will be passed + # to the block and freed afterwards. + def self.local_alloc(length, flags = LPTR, &block) + result = LocalAlloc(flags, length) + if result.null? + Chef::ReservedNames::Win32::Error.raise! + end + # If a block is passed, handle freeing the memory at the end + if block != nil + begin + yield result + ensure + local_free(result) + end + else + result + end + end + + # local_discard(pointer) + # Discard memory. Equivalent to local_realloc(pointer, 0) + def self.local_discard(pointer) + local_realloc(pointer, 0, LMEM_MOVEABLE) + end + + # local_flags(pointer) + # Get lock count and Windows flags for local_alloc allocated memory. + # Use: flags, lock_count = local_flags(pointer) + def self.local_flags(pointer) + result = LocalFlags(pointer) + if result == LMEM_INVALID_HANDLE + Chef::ReservedNames::Win32::Error.raise! + end + [ result & ~LMEM_LOCKCOUNT, result & LMEM_LOCKCOUNT ] + end + + # local_free(pointer) + # Free memory allocated using local_alloc + def self.local_free(pointer) + result = LocalFree(pointer) + if !result.null? + Chef::ReservedNames::Win32::Error.raise! + end + end + + # local_realloc(pointer, size[, flags]) + # Resizes memory allocated using LocalAlloc. + def self.local_realloc(pointer, size, flags = LMEM_MOVEABLE | LMEM_ZEROINIT) + result = LocalReAlloc(pointer, size, flags) + if result.null? + Chef::ReservedNames::Win32::Error.raise! + end + result + end + + # local_size(pointer) + # Gets the size of memory allocated using LocalAlloc. + def self.local_size(pointer) + result = LocalSize(pointer) + if result == 0 + Chef::ReservedNames::Win32::Error.raise! + end + result + end + + def self.local_free_finalizer(pointer) + proc { local_free(pointer) } + end + + end + end +end diff --git a/lib/chef/win32/process.rb b/lib/chef/win32/process.rb new file mode 100644 index 0000000000..2df39bb918 --- /dev/null +++ b/lib/chef/win32/process.rb @@ -0,0 +1,84 @@ +# +# Author:: John Keiser () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/api/process' +require 'chef/win32/api/psapi' +require 'chef/win32/error' +require 'chef/win32/handle' +require 'ffi' + +class Chef + module ReservedNames::Win32 + class Process + include Chef::ReservedNames::Win32::API::Process + extend Chef::ReservedNames::Win32::API::Process + include Chef::ReservedNames::Win32::API::PSAPI + extend Chef::ReservedNames::Win32::API::PSAPI + + def initialize(handle) + @handle = handle + end + + attr_reader :handle + + def id + Process.get_process_id(handle) + end + + def handle_count + Process.get_process_handle_count(handle) + end + + def memory_info + Process.get_process_memory_info(handle) + end + + def self.get_current_process + Process.new(Handle.new(GetCurrentProcess())) + end + + def self.get_process_handle_count(handle) + handle_count = FFI::MemoryPointer.new :uint32 + unless GetProcessHandleCount(handle.handle, handle_count) + Chef::ReservedNames::Win32::Error.raise! + end + handle_count.read_uint32 + end + + def self.get_process_id(handle) + # Must have PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION rights + result = GetProcessId(handle.handle) + if result == 0 + Chef::ReservedNames::Win32::Error.raise! + end + result + end + + # Must have PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION rights, + # AND the PROCESS_VM_READ right + def self.get_process_memory_info(handle) + memory_info = PROCESS_MEMORY_COUNTERS.new + unless GetProcessMemoryInfo(handle.handle, memory_info, memory_info.size) + Chef::ReservedNames::Win32::Error.raise! + end + memory_info + end + + end + end +end diff --git a/lib/chef/win32/security.rb b/lib/chef/win32/security.rb new file mode 100644 index 0000000000..b7b14c5652 --- /dev/null +++ b/lib/chef/win32/security.rb @@ -0,0 +1,489 @@ +# +# Author:: John Keiser () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/api/security' +require 'chef/win32/error' +require 'chef/win32/memory' +require 'chef/win32/process' +require 'chef/win32/unicode' +require 'chef/win32/security/token' + +class Chef + module ReservedNames::Win32 + class Security + include Chef::ReservedNames::Win32::API::Error + extend Chef::ReservedNames::Win32::API::Error + include Chef::ReservedNames::Win32::API::Security + extend Chef::ReservedNames::Win32::API::Security + extend Chef::ReservedNames::Win32::API::Macros + + def self.add_ace(acl, ace, insert_position = MAXDWORD, revision = ACL_REVISION) + acl = acl.pointer if acl.respond_to?(:pointer) + ace = ace.pointer if ace.respond_to?(:pointer) + ace_size = ACE_HEADER.new(ace)[:AceSize] + unless AddAce(acl, revision, insert_position, ace, ace_size) + Chef::ReservedNames::Win32::Error.raise! + end + end + + def self.add_access_allowed_ace(acl, sid, access_mask, revision = ACL_REVISION) + acl = acl.pointer if acl.respond_to?(:pointer) + sid = sid.pointer if sid.respond_to?(:pointer) + unless AddAccessAllowedAce(acl, revision, access_mask, sid) + Chef::ReservedNames::Win32::Error.raise! + end + end + + def self.add_access_allowed_ace_ex(acl, sid, access_mask, flags = 0, revision = ACL_REVISION) + acl = acl.pointer if acl.respond_to?(:pointer) + sid = sid.pointer if sid.respond_to?(:pointer) + unless AddAccessAllowedAceEx(acl, revision, flags, access_mask, sid) + Chef::ReservedNames::Win32::Error.raise! + end + end + + def self.add_access_denied_ace(acl, sid, access_mask, revision = ACL_REVISION) + acl = acl.pointer if acl.respond_to?(:pointer) + sid = sid.pointer if sid.respond_to?(:pointer) + unless AddAccessDeniedAce(acl, revision, access_mask, sid) + Chef::ReservedNames::Win32::Error.raise! + end + end + + def self.add_access_denied_ace_ex(acl, sid, access_mask, flags = 0, revision = ACL_REVISION) + acl = acl.pointer if acl.respond_to?(:pointer) + sid = sid.pointer if sid.respond_to?(:pointer) + unless AddAccessDeniedAceEx(acl, revision, flags, access_mask, sid) + Chef::ReservedNames::Win32::Error.raise! + end + end + + def self.adjust_token_privileges(token, privileges) + token = token.handle if token.respond_to?(:handle) + old_privileges_size = FFI::Buffer.new(:long).write_long(privileges.size_with_privileges) + old_privileges = TOKEN_PRIVILEGES.new(FFI::Buffer.new(old_privileges_size.read_long)) + unless AdjustTokenPrivileges(token.handle, false, privileges, privileges.size_with_privileges, old_privileges, old_privileges_size) + Chef::ReservedNames::Win32::Error.raise! + end + + old_privileges + end + + def self.convert_sid_to_string_sid(sid) + sid = sid.pointer if sid.respond_to?(:pointer) + result = FFI::MemoryPointer.new :pointer + # TODO: use the W version + unless ConvertSidToStringSidA(sid, result) + Chef::ReservedNames::Win32::Error.raise! + end + + result_string = result.read_pointer.read_string + + Chef::ReservedNames::Win32::Memory.local_free(result.read_pointer) + + result_string + end + + def self.convert_string_sid_to_sid(string_sid) + result = FFI::MemoryPointer.new :pointer + unless ConvertStringSidToSidW(string_sid.to_wstring, result) + Chef::ReservedNames::Win32::Error.raise! + end + + result_pointer = result.read_pointer + sid = SID.new(result_pointer) + + # The result pointer must be freed with local_free + ObjectSpace.define_finalizer(sid, Memory.local_free_finalizer(result_pointer)) + + sid + end + + def self.delete_ace(acl, index) + acl = acl.pointer if acl.respond_to?(:pointer) + unless DeleteAce(acl, index) + Chef::ReservedNames::Win32::Error.raise! + end + end + + def self.equal_sid(sid1, sid2) + sid1 = sid1.pointer if sid1.respond_to?(:pointer) + sid2 = sid2.pointer if sid2.respond_to?(:pointer) + EqualSid(sid1, sid2) + end + + def self.free_sid(sid) + sid = sid.pointer if sid.respond_to?(:pointer) + unless FreeSid(sid).null? + Chef::ReservedNames::Win32::Error.raise! + end + end + + def self.get_ace(acl, index) + acl = acl.pointer if acl.respond_to?(:pointer) + ace = FFI::Buffer.new :pointer + unless GetAce(acl, index, ace) + Chef::ReservedNames::Win32::Error.raise! + end + ACE.new(ace.read_pointer, acl) + end + + def self.get_length_sid(sid) + sid = sid.pointer if sid.respond_to?(:pointer) + GetLengthSid(sid) + end + + def self.get_named_security_info(path, type = :SE_FILE_OBJECT, info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION) + security_descriptor = FFI::MemoryPointer.new :pointer + hr = GetNamedSecurityInfoW(path.to_wstring, type, info, nil, nil, nil, nil, security_descriptor) + if hr != ERROR_SUCCESS + Chef::ReservedNames::Win32::Error.raise!("get_named_security_info(#{path}, #{type}, #{info})") + end + + result_pointer = security_descriptor.read_pointer + result = SecurityDescriptor.new(result_pointer) + + # This memory has to be freed with LocalFree. + ObjectSpace.define_finalizer(result, Memory.local_free_finalizer(result_pointer)) + + result + end + + def self.get_security_descriptor_control(security_descriptor) + security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) + result = FFI::Buffer.new :ushort + version = FFI::Buffer.new :uint32 + unless GetSecurityDescriptorControl(security_descriptor, result, version) + Chef::ReservedNames::Win32::Error.raise! + end + [ result.read_ushort, version.read_uint32 ] + end + + def self.get_security_descriptor_dacl(security_descriptor) + security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) + present = FFI::Buffer.new :bool + defaulted = FFI::Buffer.new :bool + acl = FFI::Buffer.new :pointer + unless GetSecurityDescriptorDacl(security_descriptor, present, acl, defaulted) + Chef::ReservedNames::Win32::Error.raise! + end + acl = acl.read_pointer + [ present.read_char != 0, acl.null? ? nil : ACL.new(acl, security_descriptor), defaulted.read_char != 0 ] + end + + def self.get_security_descriptor_group(security_descriptor) + security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) + result = FFI::Buffer.new :pointer + defaulted = FFI::Buffer.new :long + unless GetSecurityDescriptorGroup(security_descriptor, result, defaulted) + Chef::ReservedNames::Win32::Error.raise! + end + + sid = SID.new(result.read_pointer, security_descriptor) + defaulted = defaulted.read_char != 0 + [ sid, defaulted ] + end + + def self.get_security_descriptor_owner(security_descriptor) + security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) + result = FFI::Buffer.new :pointer + defaulted = FFI::Buffer.new :long + unless GetSecurityDescriptorOwner(security_descriptor, result, defaulted) + Chef::ReservedNames::Win32::Error.raise! + end + + sid = SID.new(result.read_pointer, security_descriptor) + defaulted = defaulted.read_char != 0 + [ sid, defaulted ] + end + + def self.get_security_descriptor_sacl(security_descriptor) + security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) + present = FFI::Buffer.new :bool + defaulted = FFI::Buffer.new :bool + acl = FFI::Buffer.new :pointer + unless GetSecurityDescriptorSacl(security_descriptor, present, acl, defaulted) + Chef::ReservedNames::Win32::Error.raise! + end + acl = acl.read_pointer + [ present.read_char != 0, acl.null? ? nil : ACL.new(acl, security_descriptor), defaulted.read_char != 0 ] + end + + def self.initialize_acl(acl_size) + acl = FFI::MemoryPointer.new acl_size + unless InitializeAcl(acl, acl_size, ACL_REVISION) + Chef::ReservedNames::Win32::Error.raise! + end + ACL.new(acl) + end + + def self.initialize_security_descriptor(revision = SECURITY_DESCRIPTOR_REVISION) + security_descriptor = FFI::MemoryPointer.new SECURITY_DESCRIPTOR_MIN_LENGTH + unless InitializeSecurityDescriptor(security_descriptor, revision) + Chef::ReservedNames::Win32::Error.raise! + end + SecurityDescriptor.new(security_descriptor) + end + + def self.is_valid_acl(acl) + acl = acl.pointer if acl.respond_to?(:pointer) + IsValidAcl(acl) != 0 + end + + def self.is_valid_security_descriptor(security_descriptor) + security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) + IsValidSecurityDescriptor(security_descriptor) != 0 + end + + def self.is_valid_sid(sid) + sid = sid.pointer if sid.respond_to?(:pointer) + IsValidSid(sid) != 0 + end + + def self.lookup_account_name(name, system_name = nil) + # Figure out how big the buffers need to be + sid_size = FFI::Buffer.new(:long).write_long(0) + referenced_domain_name_size = FFI::Buffer.new(:long).write_long(0) + system_name = system_name.to_wstring if system_name + if LookupAccountNameW(system_name, name.to_wstring, nil, sid_size, nil, referenced_domain_name_size, nil) + raise "Expected ERROR_INSUFFICIENT_BUFFER from LookupAccountName, and got no error!" + elsif Chef::ReservedNames::Win32::Error.get_last_error != ERROR_INSUFFICIENT_BUFFER + Chef::ReservedNames::Win32::Error.raise! + end + + sid = FFI::MemoryPointer.new :char, sid_size.read_long + referenced_domain_name = FFI::MemoryPointer.new :char, (referenced_domain_name_size.read_long*2) + use = FFI::Buffer.new(:long).write_long(0) + unless LookupAccountNameW(system_name, name.to_wstring, sid, sid_size, referenced_domain_name, referenced_domain_name_size, use) + Chef::ReservedNames::Win32::Error.raise! + end + + [ referenced_domain_name.read_wstring(referenced_domain_name_size.read_long), SID.new(sid), use.read_long ] + end + + def self.lookup_account_sid(sid, system_name = nil) + sid = sid.pointer if sid.respond_to?(:pointer) + # Figure out how big the buffer needs to be + name_size = FFI::Buffer.new(:long).write_long(0) + referenced_domain_name_size = FFI::Buffer.new(:long).write_long(0) + system_name = system_name.to_wstring if system_name + if LookupAccountSidW(system_name, sid, nil, name_size, nil, referenced_domain_name_size, nil) + raise "Expected ERROR_INSUFFICIENT_BUFFER from LookupAccountSid, and got no error!" + elsif Chef::ReservedNames::Win32::Error::get_last_error != ERROR_INSUFFICIENT_BUFFER + Chef::ReservedNames::Win32::Error.raise! + end + + name = FFI::MemoryPointer.new :char, (name_size.read_long*2) + referenced_domain_name = FFI::MemoryPointer.new :char, (referenced_domain_name_size.read_long*2) + use = FFI::Buffer.new(:long).write_long(0) + unless LookupAccountSidW(system_name, sid, name, name_size, referenced_domain_name, referenced_domain_name_size, use) + Chef::ReservedNames::Win32::Error.raise! + end + + [ referenced_domain_name.read_wstring(referenced_domain_name_size.read_long), name.read_wstring(name_size.read_long), use.read_long ] + end + + def self.lookup_privilege_name(system_name, luid) + system_name = system_name.to_wstring if system_name + name_size = FFI::Buffer.new(:long).write_long(0) + if LookupPrivilegeNameW(system_name, luid, nil, name_size) + raise "Expected ERROR_INSUFFICIENT_BUFFER from LookupPrivilegeName, and got no error!" + elsif Chef::ReservedNames::Win32::Error.get_last_error != ERROR_INSUFFICIENT_BUFFER + Chef::ReservedNames::Win32::Error.raise! + end + + name = FFI::MemoryPointer.new :char, (name_size.read_long*2) + unless LookupPrivilegeNameW(system_name, luid, name, name_size) + Chef::ReservedNames::Win32::Error.raise! + end + + name.read_wstring(name_size.read_long) + end + + def self.lookup_privilege_display_name(system_name, name) + system_name = system_name.to_wstring if system_name + display_name_size = FFI::Buffer.new(:long).write_long(0) + language_id = FFI::Buffer.new(:long) + if LookupPrivilegeDisplayNameW(system_name, name.to_wstring, nil, display_name_size, language_id) + raise "Expected ERROR_INSUFFICIENT_BUFFER from LookupPrivilegeDisplayName, and got no error!" + elsif Chef::ReservedNames::Win32::Error.get_last_error != ERROR_INSUFFICIENT_BUFFER + Chef::ReservedNames::Win32::Error.raise! + end + + display_name = FFI::MemoryPointer.new :char, (display_name_size.read_long*2) + unless LookupPrivilegeDisplayNameW(system_name, name.to_wstring, display_name, display_name_size, language_id) + Chef::ReservedNames::Win32::Error.raise! + end + + [ display_name.read_wstring(display_name_size.read_long), language_id.read_long ] + end + + def self.lookup_privilege_value(system_name, name) + luid = FFI::Buffer.new(:uint64).write_uint64(0) + system_name = system_name.to_wstring if system_name + unless LookupPrivilegeValueW(system_name, name.to_wstring, luid) + Win32::Error.raise! + end + luid.read_uint64 + end + + def self.make_absolute_sd(security_descriptor) + security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) + + # Figure out buffer sizes + absolute_sd_size = FFI::Buffer.new(:long).write_long(0) + dacl_size = FFI::Buffer.new(:long).write_long(0) + sacl_size = FFI::Buffer.new(:long).write_long(0) + owner_size = FFI::Buffer.new(:long).write_long(0) + group_size = FFI::Buffer.new(:long).write_long(0) + if MakeAbsoluteSD(security_descriptor, nil, absolute_sd_size, nil, dacl_size, nil, sacl_size, nil, owner_size, nil, group_size) + raise "Expected ERROR_INSUFFICIENT_BUFFER from MakeAbsoluteSD, and got no error!" + elsif Chef::ReservedNames::Win32::Error.get_last_error != ERROR_INSUFFICIENT_BUFFER + Chef::ReservedNames::Win32::Error.raise! + end + + absolute_sd = FFI::MemoryPointer.new absolute_sd_size.read_long + owner = FFI::MemoryPointer.new owner_size.read_long + group = FFI::MemoryPointer.new group_size.read_long + dacl = FFI::MemoryPointer.new dacl_size.read_long + sacl = FFI::MemoryPointer.new sacl_size.read_long + unless MakeAbsoluteSD(security_descriptor, absolute_sd, absolute_sd_size, dacl, dacl_size, sacl, sacl_size, owner, owner_size, group, group_size) + Chef::ReservedNames::Win32::Error.raise! + end + + [ SecurityDescriptor.new(absolute_sd), SID.new(owner), SID.new(group), ACL.new(dacl), ACL.new(sacl) ] + end + + def self.open_process_token(process, desired_access) + process = process.handle if process.respond_to?(:handle) + process = process.handle if process.respond_to?(:handle) + token = FFI::Buffer.new(:ulong) + unless OpenProcessToken(process, desired_access, token) + Chef::ReservedNames::Win32::Error.raise! + end + Token.new(Handle.new(token.read_ulong)) + end + + def self.query_security_access_mask(security_information) + result = FFI::Buffer.new(:long) + QuerySecurityAccessMask(security_information, result) + result.read_long + end + + def self.set_file_security(path, security_information, security_descriptor) + security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) + unless SetFileSecurityW(path.to_wstring, security_information, security_descriptor) + Chef::ReservedNames::Win32::Error.raise! + end + end + + def self.set_named_security_info(path, type, args) + owner = args[:owner] + group = args[:group] + dacl = args[:dacl] + sacl = args[:sacl] + owner = owner.pointer if owner && owner.respond_to?(:pointer) + group = group.pointer if group && group.respond_to?(:pointer) + dacl = dacl.pointer if dacl && dacl.respond_to?(:pointer) + sacl = sacl.pointer if sacl && sacl.respond_to?(:pointer) + + # Determine the security_information flags + security_information = 0 + security_information |= OWNER_SECURITY_INFORMATION if args.has_key?(:owner) + security_information |= GROUP_SECURITY_INFORMATION if args.has_key?(:group) + security_information |= DACL_SECURITY_INFORMATION if args.has_key?(:dacl) + security_information |= SACL_SECURITY_INFORMATION if args.has_key?(:sacl) + if args.has_key?(:dacl_inherits) + security_information |= (args[:dacl_inherits] ? UNPROTECTED_DACL_SECURITY_INFORMATION : PROTECTED_DACL_SECURITY_INFORMATION) + end + if args.has_key?(:sacl_inherits) + security_information |= (args[:sacl_inherits] ? UNPROTECTED_SACL_SECURITY_INFORMATION : PROTECTED_SACL_SECURITY_INFORMATION) + end + + hr = SetNamedSecurityInfoW(path.to_wstring, type, security_information, owner, group, dacl, sacl) + if hr != ERROR_SUCCESS + Chef::ReservedNames::Win32::Error.raise! + end + end + + def self.set_security_access_mask(security_information) + result = FFI::Buffer.new(:long) + SetSecurityAccessMask(security_information, result) + result.read_long + end + + def set_security_descriptor_dacl(security_descriptor, acl, defaulted = false, present = nil) + security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) + acl = acl.pointer if acl.respond_to?(:pointer) + present = !security_descriptor.null? if present == nil + + unless SetSecurityDescriptorDacl(security_descriptor, present, acl, defaulted) + Chef::ReservedNames::Win32::Error.raise! + end + end + + def self.set_security_descriptor_group(security_descriptor, sid, defaulted = false) + security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) + sid = sid.pointer if sid.respond_to?(:pointer) + + unless SetSecurityDescriptorGroup(security_descriptor, sid, defaulted) + Chef::ReservedNames::Win32::Error.raise! + end + end + + def self.set_security_descriptor_owner(security_descriptor, sid, defaulted = false) + security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) + sid = sid.pointer if sid.respond_to?(:pointer) + + unless SetSecurityDescriptorOwner(security_descriptor, sid, defaulted) + Chef::ReservedNames::Win32::Error.raise! + end + end + + def self.set_security_descriptor_sacl(security_descriptor, acl, defaulted = false, present = nil) + security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) + acl = acl.pointer if acl.respond_to?(:pointer) + present = !security_descriptor.null? if present == nil + + unless SetSecurityDescriptorSacl(security_descriptor, present, acl, defaulted) + Chef::ReservedNames::Win32::Error.raise! + end + end + + def self.with_privileges(*privilege_names) + # Set privileges + token = open_process_token(Chef::ReservedNames::Win32::Process.get_current_process, TOKEN_READ | TOKEN_ADJUST_PRIVILEGES) + old_privileges = token.enable_privileges(*privilege_names) + + # Let the caller do their privileged stuff + begin + yield + ensure + # Set privileges back to what they were before + token.adjust_privileges(old_privileges) + end + end + end + end +end + +require 'chef/win32/security/ace' +require 'chef/win32/security/acl' +require 'chef/win32/security/securable_object' +require 'chef/win32/security/security_descriptor' +require 'chef/win32/security/sid' diff --git a/lib/chef/win32/security/ace.rb b/lib/chef/win32/security/ace.rb new file mode 100644 index 0000000000..efd44b1c85 --- /dev/null +++ b/lib/chef/win32/security/ace.rb @@ -0,0 +1,125 @@ +# +# Author:: John Keiser () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/security' +require 'chef/win32/security/sid' +require 'chef/win32/memory' + +require 'ffi' + +class Chef + module ReservedNames::Win32 + class Security + class ACE + + def initialize(pointer, owner = nil) + if Chef::ReservedNames::Win32::API::Security::ACE_WITH_MASK_AND_SID.supports?(pointer.read_uchar) + @struct = Chef::ReservedNames::Win32::API::Security::ACE_WITH_MASK_AND_SID.new pointer + else + # TODO Support ALL the things + @struct = Chef::ReservedNames::Win32::API::Security::ACE_HEADER.new pointer + end + # Keep a reference to the actual owner of this memory so we don't get freed + @owner = owner + end + + def self.size_with_sid(sid) + Chef::ReservedNames::Win32::API::Security::ACE_WITH_MASK_AND_SID.offset_of(:SidStart) + sid.size + end + + def self.access_allowed(sid, mask, flags = 0) + create_ace_with_mask_and_sid(Chef::ReservedNames::Win32::API::Security::ACCESS_ALLOWED_ACE_TYPE, flags, mask, sid) + end + + def self.access_denied(sid, mask, flags = 0) + create_ace_with_mask_and_sid(Chef::ReservedNames::Win32::API::Security::ACCESS_DENIED_ACE_TYPE, flags, mask, sid) + end + + attr_reader :struct + + def ==(other) + type == other.type && flags == other.flags && mask == other.mask && sid == other.sid + end + + def dup + ACE.create_ace_with_mask_and_sid(type, flags, mask, sid) + end + + def flags + struct[:AceFlags] + end + + def flags=(val) + struct[:AceFlags] = val + end + + def explicit? + ! inherited? + end + + def inherited? + (struct[:AceFlags] & Chef::ReservedNames::Win32::API::Security::INHERITED_ACE) != 0 + end + + def mask + struct[:Mask] + end + + def mask=(val) + struct[:Mask] = val + end + + def pointer + struct.pointer + end + + def size + struct[:AceSize] + end + + def sid + # The SID runs off the end of the structure, starting at :SidStart. + # Use pointer arithmetic to get a pointer to that location. + Chef::ReservedNames::Win32::Security::SID.new(struct.pointer + struct.offset_of(:SidStart)) + end + + def to_s + "#{sid.account_name}/flags:#{flags.to_s(16)}/mask:#{mask.to_s(16)}" + end + + def type + struct[:AceType] + end + + private + + def self.create_ace_with_mask_and_sid(type, flags, mask, sid) + size_needed = size_with_sid(sid) + pointer = FFI::MemoryPointer.new size_needed + struct = Chef::ReservedNames::Win32::API::Security::ACE_WITH_MASK_AND_SID.new pointer + struct[:AceType] = type + struct[:AceFlags] = flags + struct[:AceSize] = size_needed + struct[:Mask] = mask + Chef::ReservedNames::Win32::Memory.memcpy(struct.pointer + struct.offset_of(:SidStart), sid.pointer, sid.size) + ACE.new(struct.pointer) + end + end + end + end +end \ No newline at end of file diff --git a/lib/chef/win32/security/acl.rb b/lib/chef/win32/security/acl.rb new file mode 100644 index 0000000000..fd43b75cbf --- /dev/null +++ b/lib/chef/win32/security/acl.rb @@ -0,0 +1,101 @@ +# +# Author:: John Keiser () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/security' +require 'chef/win32/security/ace' +require 'ffi' + +class Chef + module ReservedNames::Win32 + class Security + class ACL + include Enumerable + + def initialize(pointer, owner = nil) + @struct = Chef::ReservedNames::Win32::API::Security::ACLStruct.new pointer + # Keep a reference to the actual owner of this memory so that it isn't freed out from under us + # TODO this could be avoided if we could mark a pointer's parent manually + @owner = owner + end + + def self.create(aces) + aces_size = aces.inject(0) { |sum,ace| sum + ace.size } + acl_size = align_dword(Chef::ReservedNames::Win32::API::Security::ACLStruct.size + aces_size) # What the heck is 94??? + acl = Chef::ReservedNames::Win32::Security.initialize_acl(acl_size) + aces.each { |ace| Chef::ReservedNames::Win32::Security.add_ace(acl, ace) } + acl + end + + attr_reader :struct + + def ==(other) + return false if length != other.length + 0.upto(length-1) do |i| + return false if self[i] != other[i] + end + return true + end + + def pointer + struct.pointer + end + + def [](index) + Chef::ReservedNames::Win32::Security.get_ace(self, index) + end + + def delete_at(index) + Chef::ReservedNames::Win32::Security.delete_ace(self, index) + end + + def each + 0.upto(length-1) { |i| yield self[i] } + end + + def insert(index, *aces) + aces.reverse_each { |ace| add_ace(self, ace, index) } + end + + def length + struct[:AceCount] + end + + def push(*aces) + aces.each { |ace| Chef::ReservedNames::Win32::Security.add_ace(self, ace) } + end + + def unshift(*aces) + aces.each { |ace| Chef::ReservedNames::Win32::Security.add_ace(self, ace, 0) } + end + + def valid? + Chef::ReservedNames::Win32::Security.is_valid_acl(self) + end + + def to_s + "[#{self.collect { |ace| ace.to_s }.join(", ")}]" + end + private + + def self.align_dword(size) + (size + 4 - 1) & 0xfffffffc + end + end + end + end +end diff --git a/lib/chef/win32/security/securable_object.rb b/lib/chef/win32/security/securable_object.rb new file mode 100644 index 0000000000..00655c9bab --- /dev/null +++ b/lib/chef/win32/security/securable_object.rb @@ -0,0 +1,109 @@ +# +# Author:: John Keiser () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/security' +require 'chef/win32/security/acl' +require 'chef/win32/security/sid' + +class Chef + module ReservedNames::Win32 + class Security + class SecurableObject + + def initialize(path, type = :SE_FILE_OBJECT) + @path = path + @type = type + end + + attr_reader :path + attr_reader :type + + SecurityConst = Chef::ReservedNames::Win32::API::Security + + # This method predicts what the rights mask would be on an object + # if you created an ACE with the given mask. Specifically, it looks for + # generic attributes like GENERIC_READ, and figures out what specific + # attributes will be set. This is important if you want to try to + # compare an existing ACE with one you want to create. + def predict_rights_mask(generic_mask) + mask = generic_mask + #mask |= Chef::ReservedNames::Win32::API::Security::STANDARD_RIGHTS_READ if (mask | Chef::ReservedNames::Win32::API::Security::GENERIC_READ) != 0 + #mask |= Chef::ReservedNames::Win32::API::Security::STANDARD_RIGHTS_WRITE if (mask | Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE) != 0 + #mask |= Chef::ReservedNames::Win32::API::Security::STANDARD_RIGHTS_EXECUTE if (mask | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE) != 0 + #mask |= Chef::ReservedNames::Win32::API::Security::STANDARD_RIGHTS_ALL if (mask | Chef::ReservedNames::Win32::API::Security::GENERIC_ALL) != 0 + if type == :SE_FILE_OBJECT + mask |= Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ if (mask & Chef::ReservedNames::Win32::API::Security::GENERIC_READ) != 0 + mask |= Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE if (mask & Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE) != 0 + mask |= Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE if (mask & Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE) != 0 + mask |= Chef::ReservedNames::Win32::API::Security::FILE_ALL_ACCESS if (mask & Chef::ReservedNames::Win32::API::Security::GENERIC_ALL) != 0 + else + raise "Unimplemented object type for predict_security_mask: #{type}" + end + mask &= ~(Chef::ReservedNames::Win32::API::Security::GENERIC_READ | Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE | Chef::ReservedNames::Win32::API::Security::GENERIC_ALL) + mask + end + + def security_descriptor(include_sacl = false) + security_information = Chef::ReservedNames::Win32::API::Security::OWNER_SECURITY_INFORMATION | Chef::ReservedNames::Win32::API::Security::GROUP_SECURITY_INFORMATION | Chef::ReservedNames::Win32::API::Security::DACL_SECURITY_INFORMATION + if include_sacl + security_information |= Chef::ReservedNames::Win32::API::Security::SACL_SECURITY_INFORMATION + Security.with_privileges("SeSecurityPrivilege") do + Security.get_named_security_info(path, type, security_information) + end + else + Security.get_named_security_info(path, type, security_information) + end + end + + def dacl=(val) + Security.set_named_security_info(path, type, :dacl => val) + end + + # You don't set dacl_inherits without also setting dacl, + # because Windows gets angry and denies you access. So + # if you want to do that, you may as well do both at once. + def set_dacl(dacl, dacl_inherits) + Security.set_named_security_info(path, type, :dacl => dacl, :dacl_inherits => dacl_inherits) + end + + def group=(val) + Security.set_named_security_info(path, type, :group => val) + end + + def owner=(val) + # TODO to fix serious permissions problems, we may need to enable SeBackupPrivilege. But we might need it (almost) everywhere else, too. + Security.with_privileges("SeTakeOwnershipPrivilege", "SeRestorePrivilege") do + Security.set_named_security_info(path, type, :owner => val) + end + end + + def sacl=(val) + Security.with_privileges("SeSecurityPrivilege") do + Security.set_named_security_info(path, type, :sacl => val) + end + end + + def set_sacl(sacl, sacl_inherits) + Security.with_privileges("SeSecurityPrivilege") do + Security.set_named_security_info(path, type, :sacl => sacl, :sacl_inherits => sacl_inherits) + end + end + end + end + end +end diff --git a/lib/chef/win32/security/security_descriptor.rb b/lib/chef/win32/security/security_descriptor.rb new file mode 100644 index 0000000000..658e9104b4 --- /dev/null +++ b/lib/chef/win32/security/security_descriptor.rb @@ -0,0 +1,93 @@ +# +# Author:: John Keiser () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/security' +require 'chef/win32/security/acl' +require 'chef/win32/security/sid' + +class Chef + module ReservedNames::Win32 + class Security + class SecurityDescriptor + + def initialize(pointer) + @pointer = pointer + end + + attr_reader :pointer + + def absolute? + !self_relative? + end + + def control + control, version = Chef::ReservedNames::Win32::Security.get_security_descriptor_control(self) + control + end + + def dacl + raise "DACL not present" if !dacl_present? + present, acl, defaulted = Chef::ReservedNames::Win32::Security.get_security_descriptor_dacl(self) + acl + end + + def dacl_inherits? + (control & Chef::ReservedNames::Win32::API::Security::SE_DACL_PROTECTED) == 0 + end + + def dacl_present? + (control & Chef::ReservedNames::Win32::API::Security::SE_DACL_PRESENT) != 0 + end + + def group + result, defaulted = Chef::ReservedNames::Win32::Security.get_security_descriptor_group(self) + result + end + + def owner + result, defaulted = Chef::ReservedNames::Win32::Security.get_security_descriptor_owner(self) + result + end + + def sacl + raise "SACL not present" if !sacl_present? + Security.with_privileges("SeSecurityPrivilege") do + present, acl, defaulted = Chef::ReservedNames::Win32::Security.get_security_descriptor_sacl(self) + acl + end + end + + def sacl_inherits? + (control & Chef::ReservedNames::Win32::API::Security::SE_SACL_PROTECTED) == 0 + end + + def sacl_present? + (control & Chef::ReservedNames::Win32::API::Security::SE_SACL_PRESENT) != 0 + end + + def self_relative? + (control & Chef::ReservedNames::Win32::API::Security::SE_SELF_RELATIVE) != 0 + end + + def valid? + Chef::ReservedNames::Win32::Security.is_valid_security_descriptor(self) + end + end + end + end +end diff --git a/lib/chef/win32/security/sid.rb b/lib/chef/win32/security/sid.rb new file mode 100644 index 0000000000..7ca21eee79 --- /dev/null +++ b/lib/chef/win32/security/sid.rb @@ -0,0 +1,199 @@ +# +# Author:: John Keiser () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/security' + +class Chef + module ReservedNames::Win32 + class Security + class SID + + def initialize(pointer, owner = nil) + @pointer = pointer + # Keep a reference to the actual owner of this memory so we don't get freed + @owner = owner + end + + def self.from_account(name) + domain, sid, use = Chef::ReservedNames::Win32::Security.lookup_account_name(name) + sid + end + + def self.from_string_sid(string_sid) + Chef::ReservedNames::Win32::Security::convert_string_sid_to_sid(string_sid) + end + + def ==(other) + other != nil && Chef::ReservedNames::Win32::Security.equal_sid(self, other) + end + + attr_reader :pointer + + def account + Chef::ReservedNames::Win32::Security.lookup_account_sid(self) + end + + def account_name + domain, name, use = account + (domain != nil && domain.length > 0) ? "#{domain}\\#{name}" : name + end + + def size + Chef::ReservedNames::Win32::Security.get_length_sid(self) + end + + def to_s + Chef::ReservedNames::Win32::Security.convert_sid_to_string_sid(self) + end + + def valid? + Chef::ReservedNames::Win32::Security.is_valid_sid(self) + end + + # Well-known SIDs + def self.Null + SID.from_string_sid('S-1-0') + end + def self.Nobody + SID.from_string_sid('S-1-0-0') + end + def self.World + SID.from_string_sid('S-1-1') + end + def self.Everyone + SID.from_string_sid('S-1-1-0') + end + def self.Local + SID.from_string_sid('S-1-2') + end + def self.Creator + SID.from_string_sid('S-1-3') + end + def self.CreatorOwner + SID.from_string_sid('S-1-3-0') + end + def self.CreatorGroup + SID.from_string_sid('S-1-3-1') + end + def self.CreatorOwnerServer + SID.from_string_sid('S-1-3-2') + end + def self.CreatorGroupServer + SID.from_string_sid('S-1-3-3') + end + def self.NonUnique + SID.from_string_sid('S-1-4') + end + def self.Nt + SID.from_string_sid('S-1-5') + end + def self.Dialup + SID.from_string_sid('S-1-5-1') + end + def self.Network + SID.from_string_sid('S-1-5-2') + end + def self.Batch + SID.from_string_sid('S-1-5-3') + end + def self.Interactive + SID.from_string_sid('S-1-5-4') + end + def self.Service + SID.from_string_sid('S-1-5-6') + end + def self.Anonymous + SID.from_string_sid('S-1-5-7') + end + def self.Proxy + SID.from_string_sid('S-1-5-8') + end + def self.EnterpriseDomainControllers + SID.from_string_sid('S-1-5-9') + end + def self.PrincipalSelf + SID.from_string_sid('S-1-5-10') + end + def self.AuthenticatedUsers + SID.from_string_sid('S-1-5-11') + end + def self.RestrictedCode + SID.from_string_sid('S-1-5-12') + end + def self.TerminalServerUsers + SID.from_string_sid('S-1-5-13') + end + def self.LocalSystem + SID.from_string_sid('S-1-5-18') + end + def self.NtLocal + SID.from_string_sid('S-1-5-19') + end + def self.NtNetwork + SID.from_string_sid('S-1-5-20') + end + def self.BuiltinAdministrators + SID.from_string_sid('S-1-5-32-544') + end + def self.BuiltinUsers + SID.from_string_sid('S-1-5-32-545') + end + def self.Guests + SID.from_string_sid('S-1-5-32-546') + end + def self.PowerUsers + SID.from_string_sid('S-1-5-32-547') + end + def self.AccountOperators + SID.from_string_sid('S-1-5-32-548') + end + def self.ServerOperators + SID.from_string_sid('S-1-5-32-549') + end + def self.PrintOperators + SID.from_string_sid('S-1-5-32-550') + end + def self.BackupOperators + SID.from_string_sid('S-1-5-32-551') + end + def self.Replicators + SID.from_string_sid('S-1-5-32-552') + end + def self.Administrators + SID.from_string_sid('S-1-5-32-544') + end + + # Machine-specific, well-known SIDs + # TODO: don't use strings, dummy + def self.None + SID.from_account("#{::ENV['COMPUTERNAME']}\\None") + end + def self.Administrator + SID.from_account("#{::ENV['COMPUTERNAME']}\\Administrator") + end + def self.Guest + SID.from_account("#{::ENV['COMPUTERNAME']}\\Guest") + end + + def self.current_user + SID.from_account("#{::ENV['USERDOMAIN']}\\#{::ENV['USERNAME']}") + end + end + end + end +end \ No newline at end of file diff --git a/lib/chef/win32/security/token.rb b/lib/chef/win32/security/token.rb new file mode 100644 index 0000000000..ded4fc080e --- /dev/null +++ b/lib/chef/win32/security/token.rb @@ -0,0 +1,64 @@ +# +# Author:: John Keiser () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/security' +require 'chef/win32/api/security' + +require 'ffi' + +class Chef + module ReservedNames::Win32 + class Security + class Token + + def initialize(handle) + @handle = handle + end + + attr_reader :handle + + def enable_privileges(*privilege_names) + # Build the list of privileges we want to set + new_privileges = Chef::ReservedNames::Win32::API::Security::TOKEN_PRIVILEGES.new( + FFI::MemoryPointer.new(Chef::ReservedNames::Win32::API::Security::TOKEN_PRIVILEGES.size_with_privileges(privilege_names.length))) + new_privileges[:PrivilegeCount] = 0 + privilege_names.each do |privilege_name| + luid = Chef::ReservedNames::Win32::API::Security::LUID.new + # Ignore failure (with_privileges TRIES but does not guarantee success-- + # APIs down the line will fail if privilege escalation fails) + if Chef::ReservedNames::Win32::API::Security.LookupPrivilegeValueW(nil, privilege_name.to_wstring, luid) + new_privilege = new_privileges.privilege(new_privileges[:PrivilegeCount]) + new_privilege[:Luid][:LowPart] = luid[:LowPart] + new_privilege[:Luid][:HighPart] = luid[:HighPart] + new_privilege[:Attributes] = Chef::ReservedNames::Win32::API::Security::SE_PRIVILEGE_ENABLED + new_privileges[:PrivilegeCount] = new_privileges[:PrivilegeCount] + 1 + end + end + + old_privileges = Chef::ReservedNames::Win32::Security.adjust_token_privileges(self, new_privileges) + end + + def adjust_privileges(privileges_struct) + if privileges_struct[:PrivilegeCount] > 0 + Chef::ReservedNames::Win32::Security::adjust_token_privileges(self, privileges_struct) + end + end + end + end + end +end diff --git a/lib/chef/win32/unicode.rb b/lib/chef/win32/unicode.rb new file mode 100644 index 0000000000..1002a4d58f --- /dev/null +++ b/lib/chef/win32/unicode.rb @@ -0,0 +1,43 @@ +# +# Author:: John Keiser () +# Author:: Seth Chisamore () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/api/unicode' + +class Chef + module ReservedNames::Win32 + class Unicode + include Chef::ReservedNames::Win32::API::Unicode + extend Chef::ReservedNames::Win32::API::Unicode + end + end +end + +module FFI + class Pointer + def read_wstring(num_wchars) + Chef::ReservedNames::Win32::Unicode.wide_to_utf8(self.get_bytes(0, num_wchars*2)) + end + end +end + +class String + def to_wstring + Chef::ReservedNames::Win32::Unicode.utf8_to_wide(self) + end +end diff --git a/lib/chef/win32/version.rb b/lib/chef/win32/version.rb new file mode 100644 index 0000000000..004fcad5ad --- /dev/null +++ b/lib/chef/win32/version.rb @@ -0,0 +1,119 @@ +# +# Author:: Seth Chisamore () +# Copyright:: Copyright 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/win32/api' +require 'chef/win32/api/system' + +class Chef + module ReservedNames::Win32 + class Version + include Chef::ReservedNames::Win32::API::Macros + include Chef::ReservedNames::Win32::API::System + + # Ruby implementation of + # http://msdn.microsoft.com/en-us/library/ms724833(v=vs.85).aspx + # http://msdn.microsoft.com/en-us/library/ms724358(v=vs.85).aspx + + WIN_VERSIONS = { + "Windows 7" => {:major => 6, :minor => 1, :callable => lambda{ @product_type == VER_NT_WORKSTATION }}, + "Windows Server 2008 R2" => {:major => 6, :minor => 1, :callable => lambda{ @product_type != VER_NT_WORKSTATION }}, + "Windows Server 2008" => {:major => 6, :minor => 0, :callable => lambda{ @product_type != VER_NT_WORKSTATION }}, + "Windows Vista" => {:major => 6, :minor => 0, :callable => lambda{ @product_type == VER_NT_WORKSTATION }}, + "Windows Server 2003 R2" => {:major => 5, :minor => 2, :callable => lambda{ get_system_metrics(SM_SERVERR2) != 0 }}, + "Windows Home Server" => {:major => 5, :minor => 2, :callable => lambda{ (@suite_mask & VER_SUITE_WH_SERVER) == VER_SUITE_WH_SERVER }}, + "Windows Server 2003" => {:major => 5, :minor => 2, :callable => lambda{ get_system_metrics(SM_SERVERR2) == 0 }}, + "Windows XP" => {:major => 5, :minor => 1}, + "Windows 2000" => {:major => 5, :minor => 0} + } + + def initialize + @major_version, @minor_version, @build_number = get_version + ver_info = get_version_ex + @product_type = ver_info[:w_product_type] + @suite_mask = ver_info[:w_suite_mask] + @sp_major_version = ver_info[:w_service_pack_major] + @sp_minor_version = ver_info[:w_service_pack_minor] + @sku = get_product_info(@major_version, @minor_version, @sp_major_version, @sp_minor_version) + end + + marketing_names = Array.new + + # General Windows checks + WIN_VERSIONS.each do |k,v| + method_name = "#{k.gsub(/\s/, '_').downcase}?" + define_method(method_name) do + (@major_version == v[:major]) && + (@minor_version == v[:minor]) && + (v[:callable] ? v[:callable].call : true) + end + marketing_names << [k, method_name] + end + + define_method(:marketing_name) do + marketing_names.each do |mn| + break mn[0] if self.send(mn[1]) + end + end + + # Server Type checks + %w{ cluster core datacenter }.each do |m| + define_method("#{m}?") do + self.class.constants.any? do |c| + (self.class.const_get(c) == @sku) && + (c.to_s =~ /#{m}/i ) + end + # if @sku + # !(PRODUCT_TYPE[@sku][:name] =~ /#{m}/i).nil? + # else + # false + # end + end + end + + private + + def get_version + version = GetVersion() + major = LOBYTE(LOWORD(version)) + minor = HIBYTE(LOWORD(version)) + build = version < 0x80000000 ? HIWORD(version) : 0 + [major, minor, build] + end + + def get_version_ex + lp_version_info = OSVERSIONINFOEX.new + lp_version_info[:dw_os_version_info_size] = OSVERSIONINFOEX.size + unless GetVersionExW(lp_version_info) + Chef::ReservedNames::Win32::Error.raise! + end + lp_version_info + end + + def get_product_info(major, minor, sp_major, sp_minor) + out = FFI::MemoryPointer.new(:uint32) + GetProductInfo(major, minor, sp_major, sp_minor, out) + out.get_uint(0) + end + + def get_system_metrics(n_index) + GetSystemMetrics(n_index) + end + + end + end +end -- cgit v1.2.1