[Win32utils-devel] win32-security rough idea

Berger, Daniel Daniel.Berger at qwest.com
Mon Jul 7 16:37:17 EDT 2008


Hi all,

How does this look?

require 'win32/security'
include Win32

s = Security::SID.new('djberge')

#<Win32::Security::SID:0x2c6c56c
   @domain="mydomain",
   @host="myhost",
   @sid="\001\005\000...",
   @account_type="user",
   @account="djberge"
>

s.length       => 28
s.account      => 'djberge'
s.domain       => 'mydomain'
s.sid          => '\001...'
s.account_type => 'user'
s.to_s         => S-1-5-21-55555-444444-88-118888-999999
s.valid?       => true
s == s         => true

Here's the implementation so far (more comments at end):

# win32/security/sid.rb

require 'windows/security'
require 'windows/error'
require 'windows/msvcrt/string'
require 'windows/msvcrt/buffer'
require 'socket'

module Win32
   module Security
      class SID
         include Windows::Security
         include Windows::Error
         include Windows::MSVCRT::String
         include Windows::MSVCRT::Buffer
         extend Windows::Security
         extend Windows::Error
         extend Windows::MSVCRT::String

         class Error < StandardError; end

         # The binary SID object itself.
         attr_reader :sid

         # The account name passed to the constructor.
         attr_reader :account

         # The SID account type, e.g. 'user, 'group', etc.
         attr_reader :account_type

         # The domain the SID is on.
         attr_reader :domain

         # The host passed to the constructor, or the localhost if none
         # was specified.
         attr_reader :host

         # Converts a binary SID to a string in S-R-I-S-S... format.
         #
         def self.convert_sid_to_string_sid(sid)
            sid_addr = [sid].pack('p*').unpack('L')[0]
            sid_buf  = 0.chr * 80
            sid_ptr  = 0.chr * 4

            unless ConvertSidToStringSid(sid_addr, sid_ptr)
               raise Error, get_last_error
            end

            strcpy(sid_buf, sid_ptr.unpack('L')[0])
            sid_buf.strip
         end

         # Converts a string in S-R-I-S-S... format back to a binary
SID.
         #
         def self.convert_string_sid_to_sid(string)
            sid_buf = 0.chr * 80
            string_addr = [string].pack('p*').unpack('L')[0]

            unless ConvertStringSidToSid(string_addr, sid_buf)
               raise Error, get_last_error
            end

            sid_buf.strip
         end

         # Creates and returns a new Win32::Security::SID object, based
on
         # the account name. If a host is provided, then the information
is
         # retrieved from that host. Otherwise, the local host is used.
         #
         # Note that this does NOT create a new SID, but merely
retrieves
         # information for an existing SID. To create a new SID, use the
         # SID.create method.
         #--
         # TODO: Add the SID.create method.
         #
         def initialize(account, host=Socket.gethostname)
            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

            bool = LookupAccountName(
               host,
               account,
               sid,
               sid_cb,
               domain_buf,
               domain_cch,
               sid_name_use
            )

            unless bool
               raise Error, get_last_error
            end

            @sid     = sid.strip
            @host    = host
            @domain  = domain_buf.strip
            @account = account

            @account_type =
get_account_type(sid_name_use.unpack('L')[0])

            sid
         end

         # 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

            unless ConvertSidToStringSid(sid_addr, sid_ptr)
               raise Error, get_last_error
            end

            strcpy(sid_buf, sid_ptr.unpack('L').first)
            sid_buf.strip
         end

         alias to_str to_s

         # Returns whether or not the SID object is equal to +other+.
         #
         def ==(other)
            EqualSid(@sid, other.sid)
         end

         # Returns whether or not the SID is a valid sid.
         #
         def valid?
            IsValidSid(@sid)
         end

         # Returns the length of the SID object, in bytes.
         #
         def length
            GetLengthSid(@sid)
         end

         private

         # Converts a numeric account type into a human readable string.
         #
         def get_account_type(value)
            case value
               when SidTypeUser
                  'user'
               when SidTypeGroup
                  'group'
               when SidTypeDomain
                  'domain'
               when SidTypeAlias
                  'alias'
               when SidTypeWellKnownGroup
                  'well known group'
               when SidTypeDeletedAccount
                  'deleted account'
               when SidTypeInvalid
                  'invalid'
               when SidTypeUnknown
                  'unknown'
               when SidComputer
                  'computer'
            end
         end
      end
   end
end
# end sid.rb

I wasn't sure if SID.new should refer to an existing account, or
actually create a new SID via InitializeSid() or something. My current
idea is to setup a SID.create method for actually creating a new SID.
Does that seem reasonable? Or does that seem counterintuitive?

Anyway, there you go. Please let me know what you think.

Regards,

Dan


This communication is the property of Qwest and may contain confidential or
privileged information. Unauthorized use of this communication is strictly 
prohibited and may be unlawful.  If you have received this communication 
in error, please immediately notify the sender by reply e-mail and destroy 
all copies of the communication and any attachments.


More information about the win32utils-devel mailing list