lib/win32/security/sid.rb in win32-security-0.1.4 vs lib/win32/security/sid.rb in win32-security-0.2.0
- old
+ new
@@ -1,38 +1,25 @@
-require 'windows/security'
-require 'windows/thread'
-require 'windows/process'
-require 'windows/error'
-require 'windows/msvcrt/string'
-require 'windows/msvcrt/buffer'
+require File.join(File.dirname(__FILE__), 'windows', 'constants')
+require File.join(File.dirname(__FILE__), 'windows', 'functions')
+require File.join(File.dirname(__FILE__), 'windows', 'structs')
require 'socket'
# The Win32 module serves as a namespace only.
module Win32
# The Security class serves as a toplevel class namespace.
class Security
# The SID class encapsulates a Security Identifier.
class SID
- include Windows::Security
- include Windows::Error
- include Windows::MSVCRT::String
- include Windows::MSVCRT::Buffer
- include Windows::Thread
- include Windows::Process
+ include Windows::Security::Constants
+ include Windows::Security::Functions
+ include Windows::Security::Structs
+ extend Windows::Security::Functions
- extend Windows::Security
- extend Windows::Error
- extend Windows::MSVCRT::String
- extend Windows::MSVCRT::Buffer
-
- # Error class typically raised if any of the SID methods fail
- class Error < StandardError; end
-
# The version of the Win32::Security::SID class.
- VERSION = '0.1.4'
+ VERSION = '0.2.0'
# Some constant SID's for your convenience, in string format.
# See http://support.microsoft.com/kb/243330 for details.
Null = 'S-1-0'
@@ -89,44 +76,29 @@
attr_reader :host
# Converts a binary SID to a string in S-R-I-S-S... format.
#
def self.sid_to_string(sid)
- sid_addr = [sid].pack('p*').unpack('L')[0]
- sid_buf = 0.chr * 80
- sid_ptr = 0.chr * 4
+ string_sid = FFI::MemoryPointer.new(:pointer)
- unless ConvertSidToStringSid(sid_addr, sid_ptr)
- raise Error, get_last_error
+ unless ConvertSidToStringSid(sid, string_sid)
+ raise SystemCallError.new("ConvertSidToStringSid", FFI.errno)
end
- strcpy(sid_buf, sid_ptr.unpack('L')[0])
- sid_buf.strip
+ string_sid.read_pointer.read_string
end
# Converts a string in S-R-I-S-S... format back to a binary SID.
#
def self.string_to_sid(string)
- string_addr = [string].pack('p*').unpack('L')[0]
- sid_ptr = 0.chr * 4
+ sid = FFI::MemoryPointer.new(:pointer)
- unless ConvertStringSidToSid(string_addr, sid_ptr)
- raise Error, get_last_error
+ unless ConvertStringSidToSid(string, sid)
+ raise SystemCallError.new("ConvertStringSidToSid", FFI.errno)
end
- unless IsValidSid(sid_ptr.unpack('L')[0])
- raise Error, get_last_error
- end
-
- sid_len = GetLengthSid(sid_ptr.unpack('L')[0])
- sid_buf = 0.chr * sid_len
-
- unless CopySid(sid_len, [sid_buf].pack('p*').unpack('L')[0], sid_ptr.unpack('L')[0])
- raise Error, get_last_error
- end
-
- sid_buf
+ sid.read_pointer.read_string
end
# Creates a new SID with +authority+ and up to 8 +subauthorities+,
# and returns new Win32::Security::SID object.
#
@@ -147,28 +119,29 @@
# @domain=""
# >
#
def self.create(authority, *sub_authorities)
if sub_authorities.length > 8
- raise ArgumentError, "maximum of 8 subauthorities allowed"
+ raise ArgumentError, "maximum of 8 subauthorities allowed"
end
- sid = 0.chr * GetSidLengthRequired(sub_authorities.length)
+ size = GetSidLengthRequired(sub_authorities.length)
+ sid = FFI::MemoryPointer.new(:uchar, size)
- auth = 0.chr * 5 + authority.chr
+ auth = SID_IDENTIFIER_AUTHORITY.new
+ auth[:Value][5] = authority
unless InitializeSid(sid, auth, sub_authorities.length)
- raise Error, get_last_error
+ raise SystemCallError.new("InitializeSid", FFI.errno)
end
sub_authorities.each_index do |i|
- value = [sub_authorities[i]].pack('L')
- auth_ptr = GetSidSubAuthority(sid, i)
- memcpy(auth_ptr, value, 4)
+ ptr = GetSidSubAuthority(sid, i)
+ ptr.write_ulong(sub_authorities[i])
end
- new(sid)
+ new(sid.read_string(size)) # Pass a binary string
end
# Creates and returns a new Win32::Security::SID object, based on
# the account name, which may also be a binary SID. If a host is
# provided, then the information is retrieved from that host.
@@ -196,112 +169,121 @@
# # Binary SID
# Win32::Security::SID.new("\001\000\000\000\000\000\001\000\000\000\000")
#
def initialize(account=nil, host=Socket.gethostname)
if account.nil?
- htoken = [0].pack('L')
- bool = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, 1, htoken)
- errno = GetLastError()
+ begin
+ ptoken = FFI::MemoryPointer.new(:ulong)
- if !bool
- if errno == ERROR_NO_TOKEN
- unless OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, htoken)
- raise get_last_error
- end
+ # Try the thread token first, default to the process token.
+ bool = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, true, ptoken)
+
+ if !bool && FFI.errno != ERROR_NO_TOKEN
+ raise SystemCallError.new("OpenThreadToken", FFI.errno)
else
- raise get_last_error(errno)
+ ptoken = FFI::MemoryPointer.new(:ulong)
+ unless OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, ptoken)
+ raise SystemCallError.new("OpenProcessToken", FFI.errno)
+ end
end
- end
- htoken = htoken.unpack('V').first
- cbti = [0].pack('L')
- token_info = 0.chr * 36
+ token = ptoken.read_ulong
+ pinfo = FFI::MemoryPointer.new(:pointer)
+ plength = FFI::MemoryPointer.new(:ulong)
- bool = GetTokenInformation(
- htoken,
- TokenOwner,
- token_info,
- token_info.size,
- cbti
- )
+ # First pass, just get the size needed (1 is TokenOwner)
+ GetTokenInformation(token, 1, pinfo, pinfo.size, plength)
- unless bool
- raise Error, get_last_error
+ pinfo = FFI::MemoryPointer.new(plength.read_ulong)
+ plength = FFI::MemoryPointer.new(:ulong)
+
+ # Second pass, actual call (1 is TokenOwner)
+ unless GetTokenInformation(token, 1, pinfo, pinfo.size, plength)
+ raise SystemCallError.new("GetTokenInformation", FFI.errno)
+ end
+
+ token_info = pinfo.read_pointer
+ ensure
+ CloseHandle(token) if token
end
end
- bool = false
- sid = 0.chr * 28
- sid_cb = [sid.size].pack('L')
-
- domain_buf = 0.chr * 80
- domain_cch = [domain_buf.size].pack('L')
-
- sid_name_use = 0.chr * 4
-
if account
ordinal_val = account[0]
ordinal_val = ordinal_val.ord if RUBY_VERSION.to_f >= 1.9
else
ordinal_val = nil
end
+ sid = FFI::MemoryPointer.new(:uchar, 260)
+ sid_size = FFI::MemoryPointer.new(:ulong)
+ sid_size.write_ulong(sid.size)
+
+ domain = FFI::MemoryPointer.new(:uchar, 260)
+ domain_size = FFI::MemoryPointer.new(:ulong)
+ domain_size.write_ulong(domain.size)
+
+ use_ptr = FFI::MemoryPointer.new(:ulong)
+
if ordinal_val.nil?
bool = LookupAccountSid(
nil,
- token_info.unpack('L')[0],
+ token_info,
sid,
- sid_cb,
- domain_buf,
- domain_cch,
- sid_name_use
+ sid_size,
+ domain,
+ domain_size,
+ use_ptr
)
+ unless bool
+ raise SystemCallError.new("LookupAccountSid", FFI.errno)
+ end
elsif ordinal_val < 10 # Assume it's a binary SID.
+ account_ptr = FFI::MemoryPointer.from_string(account)
bool = LookupAccountSid(
host,
- [account].pack('p*').unpack('L')[0],
+ account_ptr,
sid,
- sid_cb,
- domain_buf,
- domain_cch,
- sid_name_use
+ sid_size,
+ domain,
+ domain_size,
+ use_ptr
)
+ unless bool
+ raise SystemCallError.new("LookupAccountSid", FFI.errno)
+ end
else
bool = LookupAccountName(
host,
account,
sid,
- sid_cb,
- domain_buf,
- domain_cch,
- sid_name_use
+ sid_size,
+ domain,
+ domain_size,
+ use_ptr,
)
+ unless bool
+ raise SystemCallError.new("LookupAccountName", FFI.errno)
+ end
end
- unless bool
- raise Error, get_last_error
- end
-
# The arguments are flipped depending on which path we took
if ordinal_val.nil?
- buf = 0.chr * 260
- ptr = token_info.unpack('L')[0]
- memcpy(buf, ptr, token_info.size)
- @sid = buf.strip
- @account = sid.strip
+ @sid = token_info.read_string
+ @account = sid.read_string(sid.size).strip
elsif ordinal_val < 10
@sid = account
- @account = sid.strip
+ @account = sid.read_string(sid.size).strip
else
- @sid = sid.strip
+ @sid = sid.read_string(sid.size).strip
@account = account
end
@host = host
- @domain = domain_buf.strip
+ @domain = domain.read_string
- @account_type = get_account_type(sid_name_use.unpack('L')[0])
+ @account_type = get_account_type(use_ptr.read_ulong)
end
# Synonym for SID.new.
#
def self.open(account=nil, host=Socket.gethostname)
@@ -310,19 +292,16 @@
# Returns the binary SID in string format suitable for display,
# storage or transmission.
#
def to_s
- sid_addr = [@sid].pack('p*').unpack('L').first
- sid_buf = 0.chr * 80
- sid_ptr = 0.chr * 4
+ ptr = FFI::MemoryPointer.new(:pointer)
- unless ConvertSidToStringSid(sid_addr, sid_ptr)
- raise Error, get_last_error
+ unless ConvertSidToStringSid(@sid, ptr)
+ raise SystemCallError.new("ConvertSidToStringSid", FFI.errno)
end
- strcpy(sid_buf, sid_ptr.unpack('L').first)
- sid_buf.strip
+ ptr.read_pointer.read_string
end
alias to_str to_s
# Returns whether or not the SID object is equal to +other+.