diff --git a/lib/puppet/util/colors.rb b/lib/puppet/util/colors.rb
index ba8a3933b..d5ded05d2 100644
--- a/lib/puppet/util/colors.rb
+++ b/lib/puppet/util/colors.rb
@@ -1,202 +1,213 @@
require 'puppet/util/platform'
module Puppet::Util::Colors
BLACK = {:console => "\e[0;30m", :html => "color: #FFA0A0" }
RED = {:console => "\e[0;31m", :html => "color: #FFA0A0" }
GREEN = {:console => "\e[0;32m", :html => "color: #00CD00" }
YELLOW = {:console => "\e[0;33m", :html => "color: #FFFF60" }
BLUE = {:console => "\e[0;34m", :html => "color: #80A0FF" }
MAGENTA = {:console => "\e[0;35m", :html => "color: #FFA500" }
CYAN = {:console => "\e[0;36m", :html => "color: #40FFFF" }
WHITE = {:console => "\e[0;37m", :html => "color: #FFFFFF" }
HBLACK = {:console => "\e[1;30m", :html => "color: #FFA0A0" }
HRED = {:console => "\e[1;31m", :html => "color: #FFA0A0" }
HGREEN = {:console => "\e[1;32m", :html => "color: #00CD00" }
HYELLOW = {:console => "\e[1;33m", :html => "color: #FFFF60" }
HBLUE = {:console => "\e[1;34m", :html => "color: #80A0FF" }
HMAGENTA = {:console => "\e[1;35m", :html => "color: #FFA500" }
HCYAN = {:console => "\e[1;36m", :html => "color: #40FFFF" }
HWHITE = {:console => "\e[1;37m", :html => "color: #FFFFFF" }
BG_RED = {:console => "\e[0;41m", :html => "background: #FFA0A0"}
BG_GREEN = {:console => "\e[0;42m", :html => "background: #00CD00"}
BG_YELLOW = {:console => "\e[0;43m", :html => "background: #FFFF60"}
BG_BLUE = {:console => "\e[0;44m", :html => "background: #80A0FF"}
BG_MAGENTA = {:console => "\e[0;45m", :html => "background: #FFA500"}
BG_CYAN = {:console => "\e[0;46m", :html => "background: #40FFFF"}
BG_WHITE = {:console => "\e[0;47m", :html => "background: #FFFFFF"}
BG_HRED = {:console => "\e[1;41m", :html => "background: #FFA0A0"}
BG_HGREEN = {:console => "\e[1;42m", :html => "background: #00CD00"}
BG_HYELLOW = {:console => "\e[1;43m", :html => "background: #FFFF60"}
BG_HBLUE = {:console => "\e[1;44m", :html => "background: #80A0FF"}
BG_HMAGENTA = {:console => "\e[1;45m", :html => "background: #FFA500"}
BG_HCYAN = {:console => "\e[1;46m", :html => "background: #40FFFF"}
BG_HWHITE = {:console => "\e[1;47m", :html => "background: #FFFFFF"}
RESET = {:console => "\e[0m", :html => "" }
Colormap = {
:debug => WHITE,
:info => GREEN,
:notice => CYAN,
:warning => YELLOW,
:err => HMAGENTA,
:alert => RED,
:emerg => HRED,
:crit => HRED,
:black => BLACK,
:red => RED,
:green => GREEN,
:yellow => YELLOW,
:blue => BLUE,
:magenta => MAGENTA,
:cyan => CYAN,
:white => WHITE,
:hblack => HBLACK,
:hred => HRED,
:hgreen => HGREEN,
:hyellow => HYELLOW,
:hblue => HBLUE,
:hmagenta => HMAGENTA,
:hcyan => HCYAN,
:hwhite => HWHITE,
:bg_red => BG_RED,
:bg_green => BG_GREEN,
:bg_yellow => BG_YELLOW,
:bg_blue => BG_BLUE,
:bg_magenta => BG_MAGENTA,
:bg_cyan => BG_CYAN,
:bg_white => BG_WHITE,
:bg_hred => BG_HRED,
:bg_hgreen => BG_HGREEN,
:bg_hyellow => BG_HYELLOW,
:bg_hblue => BG_HBLUE,
:bg_hmagenta => BG_HMAGENTA,
:bg_hcyan => BG_HCYAN,
:bg_hwhite => BG_HWHITE,
:reset => { :console => "\e[m", :html => "" }
}
# We define console_has_color? at load time since it's checking the
# underlying platform which will not change, and we don't want to perform
# the check every time we use logging
if Puppet::Util::Platform.windows?
# We're on windows, need win32console for color to work
begin
require 'ffi'
require 'win32console'
# The win32console gem uses ANSI functions for writing to the console
# which doesn't work for unicode strings, e.g. module tool. Ruby 1.9
# does the same thing, but doesn't account for ANSI escape sequences
class WideConsole < Win32::Console
extend FFI::Library
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms687401(v=vs.85).aspx
# BOOL WINAPI WriteConsole(
# _In_ HANDLE hConsoleOutput,
# _In_ const VOID *lpBuffer,
# _In_ DWORD nNumberOfCharsToWrite,
# _Out_ LPDWORD lpNumberOfCharsWritten,
# _Reserved_ LPVOID lpReserved
# );
ffi_lib :kernel32
attach_function_private :WriteConsoleW,
[:handle, :lpcwstr, :dword, :lpdword, :lpvoid], :win32_bool
# typedef struct _COORD {
# SHORT X;
# SHORT Y;
# } COORD, *PCOORD;
class COORD < FFI::Struct
layout :X, :short,
:Y, :short
end
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms687410(v=vs.85).aspx
# BOOL WINAPI WriteConsoleOutputCharacter(
# _In_ HANDLE hConsoleOutput,
# _In_ LPCTSTR lpCharacter,
# _In_ DWORD nLength,
# _In_ COORD dwWriteCoord,
# _Out_ LPDWORD lpNumberOfCharsWritten
# );
ffi_lib :kernel32
attach_function_private :WriteConsoleOutputCharacterW,
[:handle, :lpcwstr, :dword, COORD, :lpdword], :win32_bool
def initialize(t = nil)
super(t)
end
def WriteChar(str, col, row)
writeCoord = COORD.new()
writeCoord[:X] = row
writeCoord[:Y] = col
numberOfCharsWritten_ptr = FFI::MemoryPointer.new(:dword, 1)
- WriteConsoleOutputCharacterW(@handle, FFI::MemoryPointer.from_string_to_wide_string(str),
- str.length, writeCoord, numberOfCharsWritten_ptr)
- numberOfCharsWritten_ptr.read_dword
+ chars_written = 0
+ FFI::MemoryPointer.from_string_to_wide_string(str) do |msg_ptr|
+ WriteConsoleOutputCharacterW(@handle, msg_ptr,
+ str.length, writeCoord, numberOfCharsWritten_ptr)
+ chars_written = numberOfCharsWritten_ptr.read_dword
+ end
+
+ chars_written
end
def Write(str)
- WriteConsoleW(@handle, FFI::MemoryPointer.from_string_to_wide_string(str),
- str.length, FFI::MemoryPointer.new(:dword, 1), FFI::MemoryPointer::NULL)
+ result = false
+ FFI::MemoryPointer.from_string_to_wide_string(str) do |msg_ptr|
+ result = WriteConsoleW(@handle, msg_ptr,
+ str.length, FFI::MemoryPointer.new(:dword, 1),
+ FFI::MemoryPointer::NULL) != FFI::WIN32_FALSE
+ end
+
+ result
end
end
# Override the win32console's IO class so we can supply
# our own Console class
class WideIO < Win32::Console::ANSI::IO
def initialize(fd_std = :stdout)
super(fd_std)
handle = FD_STD_MAP[fd_std][1]
@Out = WideConsole.new(handle)
end
end
$stdout = WideIO.new(:stdout)
$stderr = WideIO.new(:stderr)
rescue LoadError
def console_has_color?
false
end
else
def console_has_color?
true
end
end
else
# On a posix system we can just enable it
def console_has_color?
true
end
end
def colorize(color, str)
case Puppet[:color]
when true, :ansi, "ansi", "yes"
if console_has_color?
console_color(color, str)
else
str
end
when :html, "html"
html_color(color, str)
else
str
end
end
def console_color(color, str)
Colormap[color][:console] +
str.gsub(RESET[:console], Colormap[color][:console]) +
RESET[:console]
end
def html_color(color, str)
span = '' % Colormap[color][:html]
"#{span}%s" % str.gsub(//, "\\0#{span}")
end
end
diff --git a/lib/puppet/util/windows/api_types.rb b/lib/puppet/util/windows/api_types.rb
index 8766921f9..877effcb9 100644
--- a/lib/puppet/util/windows/api_types.rb
+++ b/lib/puppet/util/windows/api_types.rb
@@ -1,151 +1,155 @@
require 'ffi'
require 'puppet/util/windows/string'
module Puppet::Util::Windows::APITypes
module ::FFI
WIN32_FALSE = 0
end
module ::FFI::Library
# Wrapper method for attach_function + private
def attach_function_private(*args)
attach_function(*args)
private args[0]
end
end
class ::FFI::Pointer
NULL_HANDLE = 0
NULL_TERMINATOR_WCHAR = 0
- def self.from_string_to_wide_string(str)
+ def self.from_string_to_wide_string(str, &block)
str = Puppet::Util::Windows::String.wide_string(str)
- ptr = FFI::MemoryPointer.new(:byte, str.bytesize)
- # uchar here is synonymous with byte
- ptr.put_array_of_uchar(0, str.bytes.to_a)
+ FFI::MemoryPointer.new(:byte, str.bytesize) do |ptr|
+ # uchar here is synonymous with byte
+ ptr.put_array_of_uchar(0, str.bytes.to_a)
- ptr
+ yield ptr
+ end
+
+ # ptr has already had free called, so nothing to return
+ nil
end
def read_win32_bool
# BOOL is always a 32-bit integer in Win32
# some Win32 APIs return 1 for true, while others are non-0
read_int32 != FFI::WIN32_FALSE
end
alias_method :read_dword, :read_uint32
def read_handle
type_size == 4 ? read_uint32 : read_uint64
end
alias_method :read_wchar, :read_uint16
def read_wide_string(char_length)
# char_length is number of wide chars (typically excluding NULLs), *not* bytes
str = get_bytes(0, char_length * 2).force_encoding('UTF-16LE')
str.encode(Encoding.default_external)
end
def read_arbitrary_wide_string_up_to(max_char_length = 512)
# max_char_length is number of wide chars (typically excluding NULLs), *not* bytes
# use a pointer to read one UTF-16LE char (2 bytes) at a time
wchar_ptr = FFI::Pointer.new(:wchar, address)
# now iterate 2 bytes at a time until an offset lower than max_char_length is found
0.upto(max_char_length - 1) do |i|
if wchar_ptr[i].read_wchar == NULL_TERMINATOR_WCHAR
return read_wide_string(i)
end
end
read_wide_string(max_char_length)
end
def read_win32_local_pointer(&block)
ptr = nil
begin
ptr = read_pointer
yield ptr
ensure
if ptr && ! ptr.null?
if FFI::WIN32::LocalFree(ptr.address) != FFI::Pointer::NULL_HANDLE
Puppet.debug "LocalFree memory leak"
end
end
end
# ptr has already had LocalFree called, so nothing to return
nil
end
alias_method :write_dword, :write_uint32
end
# FFI Types
# https://github.com/ffi/ffi/wiki/Types
# Windows - Common Data Types
# http://msdn.microsoft.com/en-us/library/cc230309.aspx
# Windows Data Types
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx
FFI.typedef :uint16, :word
FFI.typedef :uint32, :dword
# uintptr_t is defined in an FFI conf as platform specific, either
# ulong_long on x64 or just ulong on x86
FFI.typedef :uintptr_t, :handle
# buffer_inout is similar to pointer (platform specific), but optimized for buffers
FFI.typedef :buffer_inout, :lpwstr
# buffer_in is similar to pointer (platform specific), but optimized for CONST read only buffers
FFI.typedef :buffer_in, :lpcwstr
# string is also similar to pointer, but should be used for const char *
# NOTE that this is not wide, useful only for A suffixed functions
FFI.typedef :string, :lpcstr
# pointer in FFI is platform specific
# NOTE: for API calls with reserved lpvoid parameters, pass a FFI::Pointer::NULL
FFI.typedef :pointer, :lpcvoid
FFI.typedef :pointer, :lpvoid
FFI.typedef :pointer, :lpword
FFI.typedef :pointer, :lpdword
FFI.typedef :pointer, :pdword
FFI.typedef :pointer, :phandle
FFI.typedef :pointer, :ulong_ptr
FFI.typedef :pointer, :pbool
# any time LONG / ULONG is in a win32 API definition DO NOT USE platform specific width
# which is what FFI uses by default
# instead create new aliases for these very special cases
# NOTE: not a good idea to redefine FFI :ulong since other typedefs may rely on it
FFI.typedef :uint32, :win32_ulong
FFI.typedef :int32, :win32_long
# FFI bool can be only 1 byte at times,
# Win32 BOOL is a signed int, and is always 4 bytes, even on x64
# http://blogs.msdn.com/b/oldnewthing/archive/2011/03/28/10146459.aspx
FFI.typedef :int32, :win32_bool
# NOTE: FFI already defines (u)short as a 16-bit (un)signed like this:
# FFI.typedef :uint16, :ushort
# FFI.typedef :int16, :short
# 8 bits per byte
FFI.typedef :uchar, :byte
FFI.typedef :uint16, :wchar
module ::FFI::WIN32
extend ::FFI::Library
ffi_convention :stdcall
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa366730(v=vs.85).aspx
# HLOCAL WINAPI LocalFree(
# _In_ HLOCAL hMem
# );
ffi_lib :kernel32
attach_function :LocalFree, [:handle], :handle
end
end
diff --git a/lib/puppet/util/windows/sid.rb b/lib/puppet/util/windows/sid.rb
index ab5a9b638..28fa48f6d 100644
--- a/lib/puppet/util/windows/sid.rb
+++ b/lib/puppet/util/windows/sid.rb
@@ -1,152 +1,153 @@
require 'puppet/util/windows'
module Puppet::Util::Windows
module SID
require 'ffi'
extend FFI::Library
# missing from Windows::Error
ERROR_NONE_MAPPED = 1332
ERROR_INVALID_SID_STRUCTURE = 1337
# Convert an account name, e.g. 'Administrators' into a SID string,
# e.g. 'S-1-5-32-544'. The name can be specified as 'Administrators',
# 'BUILTIN\Administrators', or 'S-1-5-32-544', and will return the
# SID. Returns nil if the account doesn't exist.
def name_to_sid(name)
sid = name_to_sid_object(name)
sid ? sid.to_s : nil
end
# Convert an account name, e.g. 'Administrators' into a SID object,
# e.g. 'S-1-5-32-544'. The name can be specified as 'Administrators',
# 'BUILTIN\Administrators', or 'S-1-5-32-544', and will return the
# SID object. Returns nil if the account doesn't exist.
def name_to_sid_object(name)
# Apparently, we accept a symbol..
name = name.to_s.strip if name
# if it's in SID string form, convert to user
parsed_sid = Win32::Security::SID.string_to_sid(name) rescue nil
parsed_sid ? Win32::Security::SID.new(parsed_sid) : Win32::Security::SID.new(name)
rescue
nil
end
# Converts an octet string array of bytes to a SID object,
# e.g. [1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0] is the representation for
# S-1-5-18, the local 'SYSTEM' account.
# Raises an Error for nil or non-array input.
def octet_string_to_sid_object(bytes)
if !bytes || !bytes.respond_to?('pack') || bytes.empty?
raise Puppet::Util::Windows::Error.new("Octet string must be an array of bytes")
end
Win32::Security::SID.new(bytes.pack('C*'))
end
# Convert a SID string, e.g. "S-1-5-32-544" to a name,
# e.g. 'BUILTIN\Administrators'. Returns nil if an account
# for that SID does not exist.
def sid_to_name(value)
sid = Win32::Security::SID.new(Win32::Security::SID.string_to_sid(value))
if sid.domain and sid.domain.length > 0
"#{sid.domain}\\#{sid.account}"
else
sid.account
end
rescue
nil
end
# http://stackoverflow.com/a/1792930 - 68 bytes, 184 characters in a string
MAXIMUM_SID_STRING_LENGTH = 184
# Convert a SID pointer to a SID string, e.g. "S-1-5-32-544".
def sid_ptr_to_string(psid)
if ! psid.instance_of?(FFI::Pointer) || IsValidSid(psid) == FFI::WIN32_FALSE
raise Puppet::Util::Windows::Error.new("Invalid SID")
end
buffer_ptr = FFI::MemoryPointer.new(:pointer, 1)
if ConvertSidToStringSidW(psid, buffer_ptr) == FFI::WIN32_FALSE
raise Puppet::Util::Windows::Error.new("Failed to convert binary SID")
end
sid_string = nil
buffer_ptr.read_win32_local_pointer do |wide_string_ptr|
if wide_string_ptr.null?
raise Puppet::Error.new("ConvertSidToStringSidW failed to allocate buffer for sid")
end
sid_string = wide_string_ptr.read_arbitrary_wide_string_up_to(MAXIMUM_SID_STRING_LENGTH)
end
sid_string
end
# Convert a SID string, e.g. "S-1-5-32-544" to a pointer (containing the
# address of the binary SID structure). The returned value can be used in
# Win32 APIs that expect a PSID, e.g. IsValidSid. The account for this
# SID may or may not exist.
def string_to_sid_ptr(string_sid, &block)
- lpcwstr = FFI::MemoryPointer.from_string_to_wide_string(string_sid)
- sid_ptr_ptr = FFI::MemoryPointer.new(:pointer, 1)
+ FFI::MemoryPointer.from_string_to_wide_string(string_sid) do |lpcwstr|
+ sid_ptr_ptr = FFI::MemoryPointer.new(:pointer, 1)
- if ConvertStringSidToSidW(lpcwstr, sid_ptr_ptr) == FFI::WIN32_FALSE
- raise Puppet::Util::Windows::Error.new("Failed to convert string SID: #{string_sid}")
- end
+ if ConvertStringSidToSidW(lpcwstr, sid_ptr_ptr) == FFI::WIN32_FALSE
+ raise Puppet::Util::Windows::Error.new("Failed to convert string SID: #{string_sid}")
+ end
- sid_ptr_ptr.read_win32_local_pointer do |sid_ptr|
- yield sid_ptr
+ sid_ptr_ptr.read_win32_local_pointer do |sid_ptr|
+ yield sid_ptr
+ end
end
# yielded sid_ptr has already had LocalFree called, nothing to return
nil
end
# Return true if the string is a valid SID, e.g. "S-1-5-32-544", false otherwise.
def valid_sid?(string_sid)
valid = false
begin
string_to_sid_ptr(string_sid) { |ptr| valid = ! ptr.nil? && ! ptr.null? }
rescue Puppet::Util::Windows::Error => e
raise if e.code != ERROR_INVALID_SID_STRUCTURE
end
valid
end
ffi_convention :stdcall
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa379151(v=vs.85).aspx
# BOOL WINAPI IsValidSid(
# _In_ PSID pSid
# );
ffi_lib :advapi32
attach_function_private :IsValidSid,
[:pointer], :win32_bool
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa376399(v=vs.85).aspx
# BOOL ConvertSidToStringSid(
# _In_ PSID Sid,
# _Out_ LPTSTR *StringSid
# );
ffi_lib :advapi32
attach_function_private :ConvertSidToStringSidW,
[:pointer, :pointer], :win32_bool
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa376402(v=vs.85).aspx
# BOOL WINAPI ConvertStringSidToSid(
# _In_ LPCTSTR StringSid,
# _Out_ PSID *Sid
# );
ffi_lib :advapi32
attach_function_private :ConvertStringSidToSidW,
[:lpcwstr, :pointer], :win32_bool
end
end
diff --git a/lib/puppet/util/windows/user.rb b/lib/puppet/util/windows/user.rb
index 611584e67..7cfaa0db7 100644
--- a/lib/puppet/util/windows/user.rb
+++ b/lib/puppet/util/windows/user.rb
@@ -1,288 +1,290 @@
require 'puppet/util/windows'
require 'facter'
require 'ffi'
module Puppet::Util::Windows::User
extend Puppet::Util::Windows::String
extend FFI::Library
def admin?
majversion = Facter.value(:kernelmajversion)
return false unless majversion
# if Vista or later, check for unrestricted process token
return Puppet::Util::Windows::Process.elevated_security? unless majversion.to_f < 6.0
# otherwise 2003 or less
check_token_membership
end
module_function :admin?
# http://msdn.microsoft.com/en-us/library/windows/desktop/ee207397(v=vs.85).aspx
SECURITY_MAX_SID_SIZE = 68
def check_token_membership
sid_pointer = FFI::MemoryPointer.new(:byte, SECURITY_MAX_SID_SIZE)
size_pointer = FFI::MemoryPointer.new(:dword, 1)
size_pointer.write_uint32(SECURITY_MAX_SID_SIZE)
if CreateWellKnownSid(:WinBuiltinAdministratorsSid, FFI::Pointer::NULL, sid_pointer, size_pointer) == FFI::WIN32_FALSE
raise Puppet::Util::Windows::Error.new("Failed to create administrators SID")
end
if IsValidSid(sid_pointer) == FFI::WIN32_FALSE
raise Puppet::Util::Windows::Error.new("Invalid SID")
end
ismember_pointer = FFI::MemoryPointer.new(:win32_bool, 1)
if CheckTokenMembership(FFI::Pointer::NULL_HANDLE, sid_pointer, ismember_pointer) == FFI::WIN32_FALSE
raise Puppet::Util::Windows::Error.new("Failed to check membership")
end
# Is administrators SID enabled in calling thread's access token?
ismember_pointer.read_win32_bool
end
module_function :check_token_membership
def password_is?(name, password)
logon_user(name, password)
true
rescue Puppet::Util::Windows::Error
false
end
module_function :password_is?
def logon_user(name, password, &block)
fLOGON32_LOGON_NETWORK = 3
fLOGON32_PROVIDER_DEFAULT = 0
token_pointer = FFI::MemoryPointer.new(:handle, 1)
if LogonUserW(wide_string(name), wide_string('.'), wide_string(password),
fLOGON32_LOGON_NETWORK, fLOGON32_PROVIDER_DEFAULT, token_pointer) == FFI::WIN32_FALSE
raise Puppet::Util::Windows::Error.new("Failed to logon user #{name.inspect}")
end
token = token_pointer.read_handle
begin
yield token if block_given?
ensure
CloseHandle(token)
end
end
module_function :logon_user
def load_profile(user, password)
logon_user(user, password) do |token|
- pi = PROFILEINFO.new
- pi[:dwSize] = PROFILEINFO.size
- pi[:dwFlags] = 1 # PI_NOUI - prevents display of profile error msgs
- pi[:lpUserName] = FFI::MemoryPointer.from_string_to_wide_string(user)
+ FFI::MemoryPointer.from_string_to_wide_string(user) do |lpUserName|
+ pi = PROFILEINFO.new
+ pi[:dwSize] = PROFILEINFO.size
+ pi[:dwFlags] = 1 # PI_NOUI - prevents display of profile error msgs
+ pi[:lpUserName] = lpUserName
- # Load the profile. Since it doesn't exist, it will be created
- if LoadUserProfileW(token, pi.pointer) == FFI::WIN32_FALSE
- raise Puppet::Util::Windows::Error.new("Failed to load user profile #{user.inspect}")
- end
+ # Load the profile. Since it doesn't exist, it will be created
+ if LoadUserProfileW(token, pi.pointer) == FFI::WIN32_FALSE
+ raise Puppet::Util::Windows::Error.new("Failed to load user profile #{user.inspect}")
+ end
- Puppet.debug("Loaded profile for #{user}")
+ Puppet.debug("Loaded profile for #{user}")
- if UnloadUserProfile(token, pi[:hProfile]) == FFI::WIN32_FALSE
- raise Puppet::Util::Windows::Error.new("Failed to unload user profile #{user.inspect}")
+ if UnloadUserProfile(token, pi[:hProfile]) == FFI::WIN32_FALSE
+ raise Puppet::Util::Windows::Error.new("Failed to unload user profile #{user.inspect}")
+ end
end
end
end
module_function :load_profile
ffi_convention :stdcall
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa378184(v=vs.85).aspx
# BOOL LogonUser(
# _In_ LPTSTR lpszUsername,
# _In_opt_ LPTSTR lpszDomain,
# _In_opt_ LPTSTR lpszPassword,
# _In_ DWORD dwLogonType,
# _In_ DWORD dwLogonProvider,
# _Out_ PHANDLE phToken
# );
ffi_lib :advapi32
attach_function_private :LogonUserW,
[:lpwstr, :lpwstr, :lpwstr, :dword, :dword, :phandle], :win32_bool
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx
# BOOL WINAPI CloseHandle(
# _In_ HANDLE hObject
# );
ffi_lib :kernel32
attach_function_private :CloseHandle, [:handle], :win32_bool
# http://msdn.microsoft.com/en-us/library/windows/desktop/bb773378(v=vs.85).aspx
# typedef struct _PROFILEINFO {
# DWORD dwSize;
# DWORD dwFlags;
# LPTSTR lpUserName;
# LPTSTR lpProfilePath;
# LPTSTR lpDefaultPath;
# LPTSTR lpServerName;
# LPTSTR lpPolicyPath;
# HANDLE hProfile;
# } PROFILEINFO, *LPPROFILEINFO;
# technically
# NOTE: that for structs, buffer_* (lptstr alias) cannot be used
class PROFILEINFO < FFI::Struct
layout :dwSize, :dword,
:dwFlags, :dword,
:lpUserName, :pointer,
:lpProfilePath, :pointer,
:lpDefaultPath, :pointer,
:lpServerName, :pointer,
:lpPolicyPath, :pointer,
:hProfile, :handle
end
# http://msdn.microsoft.com/en-us/library/windows/desktop/bb762281(v=vs.85).aspx
# BOOL WINAPI LoadUserProfile(
# _In_ HANDLE hToken,
# _Inout_ LPPROFILEINFO lpProfileInfo
# );
ffi_lib :userenv
attach_function_private :LoadUserProfileW,
[:handle, :pointer], :win32_bool
# http://msdn.microsoft.com/en-us/library/windows/desktop/bb762282(v=vs.85).aspx
# BOOL WINAPI UnloadUserProfile(
# _In_ HANDLE hToken,
# _In_ HANDLE hProfile
# );
ffi_lib :userenv
attach_function_private :UnloadUserProfile,
[:handle, :handle], :win32_bool
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa376389(v=vs.85).aspx
# BOOL WINAPI CheckTokenMembership(
# _In_opt_ HANDLE TokenHandle,
# _In_ PSID SidToCheck,
# _Out_ PBOOL IsMember
# );
ffi_lib :advapi32
attach_function_private :CheckTokenMembership,
[:handle, :pointer, :pbool], :win32_bool
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa379650(v=vs.85).aspx
WELL_KNOWN_SID_TYPE = enum(
:WinNullSid , 0,
:WinWorldSid , 1,
:WinLocalSid , 2,
:WinCreatorOwnerSid , 3,
:WinCreatorGroupSid , 4,
:WinCreatorOwnerServerSid , 5,
:WinCreatorGroupServerSid , 6,
:WinNtAuthoritySid , 7,
:WinDialupSid , 8,
:WinNetworkSid , 9,
:WinBatchSid , 10,
:WinInteractiveSid , 11,
:WinServiceSid , 12,
:WinAnonymousSid , 13,
:WinProxySid , 14,
:WinEnterpriseControllersSid , 15,
:WinSelfSid , 16,
:WinAuthenticatedUserSid , 17,
:WinRestrictedCodeSid , 18,
:WinTerminalServerSid , 19,
:WinRemoteLogonIdSid , 20,
:WinLogonIdsSid , 21,
:WinLocalSystemSid , 22,
:WinLocalServiceSid , 23,
:WinNetworkServiceSid , 24,
:WinBuiltinDomainSid , 25,
:WinBuiltinAdministratorsSid , 26,
:WinBuiltinUsersSid , 27,
:WinBuiltinGuestsSid , 28,
:WinBuiltinPowerUsersSid , 29,
:WinBuiltinAccountOperatorsSid , 30,
:WinBuiltinSystemOperatorsSid , 31,
:WinBuiltinPrintOperatorsSid , 32,
:WinBuiltinBackupOperatorsSid , 33,
:WinBuiltinReplicatorSid , 34,
:WinBuiltinPreWindows2000CompatibleAccessSid , 35,
:WinBuiltinRemoteDesktopUsersSid , 36,
:WinBuiltinNetworkConfigurationOperatorsSid , 37,
:WinAccountAdministratorSid , 38,
:WinAccountGuestSid , 39,
:WinAccountKrbtgtSid , 40,
:WinAccountDomainAdminsSid , 41,
:WinAccountDomainUsersSid , 42,
:WinAccountDomainGuestsSid , 43,
:WinAccountComputersSid , 44,
:WinAccountControllersSid , 45,
:WinAccountCertAdminsSid , 46,
:WinAccountSchemaAdminsSid , 47,
:WinAccountEnterpriseAdminsSid , 48,
:WinAccountPolicyAdminsSid , 49,
:WinAccountRasAndIasServersSid , 50,
:WinNTLMAuthenticationSid , 51,
:WinDigestAuthenticationSid , 52,
:WinSChannelAuthenticationSid , 53,
:WinThisOrganizationSid , 54,
:WinOtherOrganizationSid , 55,
:WinBuiltinIncomingForestTrustBuildersSid , 56,
:WinBuiltinPerfMonitoringUsersSid , 57,
:WinBuiltinPerfLoggingUsersSid , 58,
:WinBuiltinAuthorizationAccessSid , 59,
:WinBuiltinTerminalServerLicenseServersSid , 60,
:WinBuiltinDCOMUsersSid , 61,
:WinBuiltinIUsersSid , 62,
:WinIUserSid , 63,
:WinBuiltinCryptoOperatorsSid , 64,
:WinUntrustedLabelSid , 65,
:WinLowLabelSid , 66,
:WinMediumLabelSid , 67,
:WinHighLabelSid , 68,
:WinSystemLabelSid , 69,
:WinWriteRestrictedCodeSid , 70,
:WinCreatorOwnerRightsSid , 71,
:WinCacheablePrincipalsGroupSid , 72,
:WinNonCacheablePrincipalsGroupSid , 73,
:WinEnterpriseReadonlyControllersSid , 74,
:WinAccountReadonlyControllersSid , 75,
:WinBuiltinEventLogReadersGroup , 76,
:WinNewEnterpriseReadonlyControllersSid , 77,
:WinBuiltinCertSvcDComAccessGroup , 78,
:WinMediumPlusLabelSid , 79,
:WinLocalLogonSid , 80,
:WinConsoleLogonSid , 81,
:WinThisOrganizationCertificateSid , 82,
:WinApplicationPackageAuthoritySid , 83,
:WinBuiltinAnyPackageSid , 84,
:WinCapabilityInternetClientSid , 85,
:WinCapabilityInternetClientServerSid , 86,
:WinCapabilityPrivateNetworkClientServerSid , 87,
:WinCapabilityPicturesLibrarySid , 88,
:WinCapabilityVideosLibrarySid , 89,
:WinCapabilityMusicLibrarySid , 90,
:WinCapabilityDocumentsLibrarySid , 91,
:WinCapabilitySharedUserCertificatesSid , 92,
:WinCapabilityEnterpriseAuthenticationSid , 93,
:WinCapabilityRemovableStorageSid , 94
)
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa446585(v=vs.85).aspx
# BOOL WINAPI CreateWellKnownSid(
# _In_ WELL_KNOWN_SID_TYPE WellKnownSidType,
# _In_opt_ PSID DomainSid,
# _Out_opt_ PSID pSid,
# _Inout_ DWORD *cbSid
# );
ffi_lib :advapi32
attach_function_private :CreateWellKnownSid,
[WELL_KNOWN_SID_TYPE, :pointer, :pointer, :lpdword], :win32_bool
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa379151(v=vs.85).aspx
# BOOL WINAPI IsValidSid(
# _In_ PSID pSid
# );
ffi_lib :advapi32
attach_function_private :IsValidSid,
[:pointer], :win32_bool
end
diff --git a/spec/unit/util/windows/api_types_spec.rb b/spec/unit/util/windows/api_types_spec.rb
index 75d591edd..a1e1c76c9 100644
--- a/spec/unit/util/windows/api_types_spec.rb
+++ b/spec/unit/util/windows/api_types_spec.rb
@@ -1,24 +1,28 @@
# encoding: UTF-8
#!/usr/bin/env ruby
require 'spec_helper'
describe "FFI::MemoryPointer", :if => Puppet.features.microsoft_windows? do
context "read_wide_string" do
let (:string) { "foo_bar" }
it "should properly roundtrip a given string" do
- ptr = FFI::MemoryPointer.from_string_to_wide_string(string)
- read_string = ptr.read_wide_string(string.length)
+ read_string = nil
+ FFI::MemoryPointer.from_string_to_wide_string(string) do |ptr|
+ read_string = ptr.read_wide_string(string.length)
+ end
read_string.should == string
end
it "should return a given string in the default encoding" do
- ptr = FFI::MemoryPointer.from_string_to_wide_string(string)
- read_string = ptr.read_wide_string(string.length)
+ read_string = nil
+ FFI::MemoryPointer.from_string_to_wide_string(string) do |ptr|
+ read_string = ptr.read_wide_string(string.length)
+ end
read_string.encoding.should == Encoding.default_external
end
end
end