win32-security 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGES CHANGED
@@ -1,3 +1,7 @@
1
+ == 0.2.0 - 11-Jan-2013
2
+ * Converted the code to FFI.
3
+ * Refactored some of the tests.
4
+
1
5
  = 0.1.4 - 4-Oct-2012
2
6
  * Updated the SID.string_to_sid method so that it completes a string/sid
3
7
  round trip successfully now. Thanks go to Josh Cooper for the patch.
data/MANIFEST CHANGED
@@ -1,9 +1,9 @@
1
- * CHANGES
2
- * MANIFEST
3
- * README
4
- * Rakefile
5
- * win32-security.gemspec
6
- * lib/win32/security.rb
7
- * lib/win32/security/sid.rb
8
- * test/test_security.rb
1
+ * CHANGES
2
+ * MANIFEST
3
+ * README
4
+ * Rakefile
5
+ * win32-security.gemspec
6
+ * lib/win32/security.rb
7
+ * lib/win32/security/sid.rb
8
+ * test/test_security.rb
9
9
  * test/test_sid.rb
data/README CHANGED
@@ -27,7 +27,7 @@
27
27
  Artistic 2.0
28
28
 
29
29
  == Copyright
30
- (C) 2003-2012 Daniel J. Berger
30
+ (C) 2003-2013 Daniel J. Berger
31
31
  All Rights Reserved
32
32
 
33
33
  == Authors
data/Rakefile CHANGED
@@ -1,13 +1,11 @@
1
1
  require 'rake'
2
+ require 'rake/clean'
2
3
  require 'rake/testtask'
3
4
  require 'rbconfig'
4
5
 
5
- namespace :gem do
6
- desc "Remove any .gem files in the project"
7
- task :clean do
8
- Dir['*.gem'].each{ |f| File.delete(f) }
9
- end
6
+ CLEAN.include('**/*.gem', '**/*.rbc')
10
7
 
8
+ namespace :gem do
11
9
  desc "Create the win32-security gem"
12
10
  task :create => [:clean] do
13
11
  spec = eval(IO.read('win32-security.gemspec'))
@@ -29,6 +27,12 @@ namespace :test do
29
27
  t.test_files = Dir['test/test_security.rb']
30
28
  end
31
29
 
30
+ Rake::TestTask.new(:acl) do |t|
31
+ t.verbose = true
32
+ t.warning = true
33
+ t.test_files = Dir['test/test_acl.rb']
34
+ end
35
+
32
36
  Rake::TestTask.new(:sid) do |t|
33
37
  t.verbose = true
34
38
  t.warning = true
@@ -1,10 +1,9 @@
1
1
  # This file allows users to require all security related classes from
2
2
  # a single file, instead of having to require individual files.
3
3
 
4
- require 'windows/process'
5
- require 'windows/security'
6
- require 'windows/handle'
7
- require 'windows/error'
4
+ require File.join(File.dirname(__FILE__), 'security', 'windows', 'constants')
5
+ require File.join(File.dirname(__FILE__), 'security', 'windows', 'structs')
6
+ require File.join(File.dirname(__FILE__), 'security', 'windows', 'functions')
8
7
 
9
8
  # The Win32 module serves as a namespace only.
10
9
  module Win32
@@ -15,53 +14,97 @@ module Win32
15
14
  # Base error class for all Win32::Security errors.
16
15
  class Error < StandardError; end
17
16
 
18
- include Windows::Security
19
-
20
- extend Windows::Process
21
- extend Windows::Security
22
- extend Windows::Handle
23
- extend Windows::Error
17
+ include Windows::Security::Functions
18
+ include Windows::Security::Constants
19
+ include Windows::Security::Structs
20
+ extend Windows::Security::Functions
24
21
 
25
22
  # The version of the win32-security library
26
- VERSION = '0.1.4'
23
+ VERSION = '0.2.0'
24
+
25
+ # Used by OpenProcessToken
26
+ TOKEN_QUERY = 8
27
27
 
28
28
  # Returns whether or not the owner of the current process is running
29
29
  # with elevated security privileges.
30
30
  #
31
- # Only supported on Windows Vista or later.
31
+ # On Windows XP an earlier this method is actually just checking to
32
+ # see if the caller's process is a member of the local Administrator's
33
+ # group.
32
34
  #
33
35
  def self.elevated_security?
34
- token = 0.chr * 4
36
+ if windows_version < 6
37
+ sid_ptr = FFI::MemoryPointer.new(:pointer)
38
+ nt_auth_ptr = FFI::MemoryPointer.new(SID_IDENTIFIER_AUTHORITY,1)
35
39
 
36
- unless OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, token)
37
- raise Error, get_last_error
38
- end
40
+ nt_auth = SID_IDENTIFIER_AUTHORITY.new(nt_auth_ptr)
41
+ nt_auth[:Value].to_ptr.put_bytes(0, 0.chr*5 + 5.chr)
42
+
43
+ bool = AllocateAndInitializeSid(
44
+ nt_auth_ptr,
45
+ 2,
46
+ SECURITY_BUILTIN_DOMAIN_RID,
47
+ DOMAIN_ALIAS_RID_ADMINS,
48
+ 0, 0, 0, 0, 0, 0,
49
+ sid_ptr
50
+ )
51
+ unless bool
52
+ raise SystemCallError.new("AllocateAndInitializeSid", FFI.errno)
53
+ end
39
54
 
40
- begin
41
- token = token.unpack('V')[0]
55
+ pbool = FFI::MemoryPointer.new(:long)
42
56
 
43
- te = 0.chr * 4 # TOKEN_ELEVATION
44
- rl = 0.chr * 4 # Return length
57
+ unless CheckTokenMembership(0, sid_ptr.read_pointer, pbool)
58
+ raise SystemCallError.new("CheckTokenMembership", FFI.errno)
59
+ end
45
60
 
46
- bool = GetTokenInformation(
47
- token,
48
- TokenElevation,
49
- te,
50
- te.size,
51
- rl
52
- )
61
+ pbool.read_long != 0
62
+ else
63
+ token = FFI::MemoryPointer.new(:ulong)
64
+
65
+ unless OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, token)
66
+ raise SystemCallError.new("OpenProcessToken", FFI.errno)
67
+ end
68
+
69
+ begin
70
+ token = token.read_ulong
71
+
72
+ # Since the TokenElevation struct only has 1 member, we use a pointer.
73
+ te = FFI::MemoryPointer.new(:ulong)
74
+ rl = FFI::MemoryPointer.new(:ulong)
75
+
76
+ bool = GetTokenInformation(
77
+ token,
78
+ :TokenElevation,
79
+ te,
80
+ te.size,
81
+ rl
82
+ )
83
+
84
+ raise SystemCallError.new("GetTokenInformation", FFI.errno) unless bool
85
+ ensure
86
+ CloseHandle(token)
87
+ end
88
+
89
+ te.read_ulong != 0
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ def self.windows_version
96
+ ver = OSVERSIONINFO.new
97
+ ver[:dwOSVersionInfoSize] = ver.size
53
98
 
54
- raise Error, get_last_error unless bool
55
- ensure
56
- CloseHandle(token)
99
+ unless GetVersionExA(ver)
100
+ raise SystemCallError.new("GetVersionEx", FFI.errno)
57
101
  end
58
102
 
59
- # TokenIsElevated member of the TOKEN_ELEVATION struct
60
- te.unpack('L')[0] != 0
103
+ ver[:dwMajorVersion]
61
104
  end
62
105
  end
63
106
  end
64
107
 
65
108
  require 'win32/security/sid'
66
- #require 'win32/security/acl'
109
+ require 'win32/security/acl'
67
110
  #require 'win32/security/ace'
@@ -1,25 +1,24 @@
1
- require 'windows/security'
2
- require 'windows/error'
3
- require 'windows/limits'
4
- require 'windows/msvcrt/buffer'
1
+ require File.join(File.dirname(__FILE__), 'windows', 'constants')
2
+ require File.join(File.dirname(__FILE__), 'windows', 'structs')
3
+ require File.join(File.dirname(__FILE__), 'windows', 'functions')
5
4
 
6
5
  # The Win32 module serves as a namespace only.
7
6
  module Win32
8
-
7
+
9
8
  # The Security class serves as a toplevel class namespace.
10
9
  class Security
11
-
10
+
12
11
  # The ACL class encapsulates an Access Control List.
13
12
  class ACL
14
- include Windows::Error
15
- include Windows::Security
16
- include Windows::Limits
17
- include Windows::MSVCRT::Buffer
18
-
13
+ include Windows::Security::Constants
14
+ include Windows::Security::Functions
15
+ include Windows::Security::Structs
16
+ extend Windows::Security::Functions
17
+
19
18
  # The version of the Win32::Security::ACL class.
20
- VERSION = '0.1.0'
19
+ VERSION = '0.2.0'
21
20
 
22
- # The binary representation of the ACL structure
21
+ # The underlying ACL structure.
23
22
  attr_reader :acl
24
23
 
25
24
  # The revision level.
@@ -30,10 +29,10 @@ module Win32
30
29
  # the ACL itself, and the revision information.
31
30
  #
32
31
  def initialize(revision = ACL_REVISION)
33
- acl = 0.chr * 8 # This can be increased later as needed
32
+ acl = ACL_STRUCT.new
34
33
 
35
34
  unless InitializeAcl(acl, acl.size, revision)
36
- raise Error, get_last_error
35
+ raise SystemCallError.new("InitializeAcl", FFI.errno)
37
36
  end
38
37
 
39
38
  @acl = acl
@@ -43,21 +42,22 @@ module Win32
43
42
  # Returns the number of ACE's in the ACL object.
44
43
  #
45
44
  def ace_count
46
- buf = 0.chr * 12 # sizeof(ACL_SIZE_INFORMATION)
45
+ info = ACL_SIZE_INFORMATION.new
47
46
 
48
- unless GetAclInformation(@acl, buf, buf.size, AclSizeInformation)
49
- raise Error, get_last_error
47
+ unless GetAclInformation(@acl, info, info.size, AclSizeInformation)
48
+ raise SystemCallError.new("GetAclInformation", FFI.errno)
50
49
  end
51
50
 
52
- buf[0, 4].unpack('L')[0]
51
+ info[:AceCount]
53
52
  end
54
53
 
55
54
  # Adds an access allowed ACE to the given +sid+. The +mask+ is a
56
55
  # bitwise OR'd value of access rights.
57
56
  #
57
+ # TODO: Move this into the SID class?
58
58
  def add_access_allowed_ace(sid, mask=0)
59
59
  unless AddAccessAllowedAce(@acl, @revision, mask, sid)
60
- raise Error, get_last_error
60
+ raise SystemCallError.new("AddAccessAllowedAce", FFI.errno)
61
61
  end
62
62
  end
63
63
 
@@ -65,7 +65,7 @@ module Win32
65
65
  #
66
66
  def add_access_denied_ace(sid, mask=0)
67
67
  unless AddAccessDeniedAce(@acl, @revision, mask, sid)
68
- raise Error, get_last_error
68
+ raise SystemCallError.new("AddAccessDeniedAce", FFI.errno)
69
69
  end
70
70
  end
71
71
 
@@ -79,7 +79,7 @@ module Win32
79
79
  #
80
80
  def add_ace(ace, index=MAXDWORD)
81
81
  unless AddAce(@acl, @revision, index, ace, ace.length)
82
- raise Error, get_last_error
82
+ raise SystemCallError.new("AddAce", FFI.errno)
83
83
  end
84
84
 
85
85
  index
@@ -95,7 +95,7 @@ module Win32
95
95
  #
96
96
  def delete_ace(index=MAXDWORD)
97
97
  unless DeleteAce(@ace, index)
98
- raise Error, get_last_error
98
+ raise SystemCallError.new("DeleteAce", FFI.errno)
99
99
  end
100
100
 
101
101
  index
@@ -106,19 +106,19 @@ module Win32
106
106
  # first free byte of the ACL is returned.
107
107
  #
108
108
  def find_ace(index = nil)
109
- ptr = [0].pack('L')
109
+ pptr = FFI::MemoryPointer.new(:pointer)
110
110
 
111
111
  if index.nil?
112
- unless FindFirstFreeAce(@acl, ptr)
113
- raise Error, get_last_error
112
+ unless FindFirstFreeAce(@acl, pptr)
113
+ raise SystemCallError.new("DeleteAce", FFI.errno)
114
114
  end
115
115
  else
116
- unless GetAce(@acl, index, ptr)
117
- raise Error, get_last_error
116
+ unless GetAce(@acl, index, pptr)
117
+ raise SystemCallError.new("GetAce", FFI.errno)
118
118
  end
119
119
  end
120
120
 
121
- [ptr].pack('p*').unpack('L')[0]
121
+ pptr.read_pointer.address
122
122
  end
123
123
 
124
124
  # Sets the revision information level, where the +revision_level+
@@ -127,10 +127,11 @@ module Win32
127
127
  # Returns the revision level if successful.
128
128
  #
129
129
  def revision=(revision_level)
130
- buf = [revision_level].pack('L')
130
+ buf = FFI::MemoryPointer.new(:ulong)
131
+ buf.write_ulong(revision_level)
131
132
 
132
133
  unless SetAclInformation(@acl, buf, buf.size, AclRevisionInformation)
133
- raise Error, get_last_error
134
+ raise SystemCallError.new("SetAclInformation", FFI.errno)
134
135
  end
135
136
 
136
137
  @revision = revision_level
@@ -1,9 +1,6 @@
1
- require 'windows/security'
2
- require 'windows/thread'
3
- require 'windows/process'
4
- require 'windows/error'
5
- require 'windows/msvcrt/string'
6
- require 'windows/msvcrt/buffer'
1
+ require File.join(File.dirname(__FILE__), 'windows', 'constants')
2
+ require File.join(File.dirname(__FILE__), 'windows', 'functions')
3
+ require File.join(File.dirname(__FILE__), 'windows', 'structs')
7
4
  require 'socket'
8
5
 
9
6
  # The Win32 module serves as a namespace only.
@@ -14,23 +11,13 @@ module Win32
14
11
 
15
12
  # The SID class encapsulates a Security Identifier.
16
13
  class SID
17
- include Windows::Security
18
- include Windows::Error
19
- include Windows::MSVCRT::String
20
- include Windows::MSVCRT::Buffer
21
- include Windows::Thread
22
- include Windows::Process
23
-
24
- extend Windows::Security
25
- extend Windows::Error
26
- extend Windows::MSVCRT::String
27
- extend Windows::MSVCRT::Buffer
28
-
29
- # Error class typically raised if any of the SID methods fail
30
- class Error < StandardError; end
14
+ include Windows::Security::Constants
15
+ include Windows::Security::Functions
16
+ include Windows::Security::Structs
17
+ extend Windows::Security::Functions
31
18
 
32
19
  # The version of the Win32::Security::SID class.
33
- VERSION = '0.1.4'
20
+ VERSION = '0.2.0'
34
21
 
35
22
  # Some constant SID's for your convenience, in string format.
36
23
  # See http://support.microsoft.com/kb/243330 for details.
@@ -91,40 +78,25 @@ module Win32
91
78
  # Converts a binary SID to a string in S-R-I-S-S... format.
92
79
  #
93
80
  def self.sid_to_string(sid)
94
- sid_addr = [sid].pack('p*').unpack('L')[0]
95
- sid_buf = 0.chr * 80
96
- sid_ptr = 0.chr * 4
81
+ string_sid = FFI::MemoryPointer.new(:pointer)
97
82
 
98
- unless ConvertSidToStringSid(sid_addr, sid_ptr)
99
- raise Error, get_last_error
83
+ unless ConvertSidToStringSid(sid, string_sid)
84
+ raise SystemCallError.new("ConvertSidToStringSid", FFI.errno)
100
85
  end
101
86
 
102
- strcpy(sid_buf, sid_ptr.unpack('L')[0])
103
- sid_buf.strip
87
+ string_sid.read_pointer.read_string
104
88
  end
105
89
 
106
90
  # Converts a string in S-R-I-S-S... format back to a binary SID.
107
91
  #
108
92
  def self.string_to_sid(string)
109
- string_addr = [string].pack('p*').unpack('L')[0]
110
- sid_ptr = 0.chr * 4
93
+ sid = FFI::MemoryPointer.new(:pointer)
111
94
 
112
- unless ConvertStringSidToSid(string_addr, sid_ptr)
113
- raise Error, get_last_error
95
+ unless ConvertStringSidToSid(string, sid)
96
+ raise SystemCallError.new("ConvertStringSidToSid", FFI.errno)
114
97
  end
115
98
 
116
- unless IsValidSid(sid_ptr.unpack('L')[0])
117
- raise Error, get_last_error
118
- end
119
-
120
- sid_len = GetLengthSid(sid_ptr.unpack('L')[0])
121
- sid_buf = 0.chr * sid_len
122
-
123
- unless CopySid(sid_len, [sid_buf].pack('p*').unpack('L')[0], sid_ptr.unpack('L')[0])
124
- raise Error, get_last_error
125
- end
126
-
127
- sid_buf
99
+ sid.read_pointer.read_string
128
100
  end
129
101
 
130
102
  # Creates a new SID with +authority+ and up to 8 +subauthorities+,
@@ -149,24 +121,25 @@ module Win32
149
121
  #
150
122
  def self.create(authority, *sub_authorities)
151
123
  if sub_authorities.length > 8
152
- raise ArgumentError, "maximum of 8 subauthorities allowed"
124
+ raise ArgumentError, "maximum of 8 subauthorities allowed"
153
125
  end
154
126
 
155
- sid = 0.chr * GetSidLengthRequired(sub_authorities.length)
127
+ size = GetSidLengthRequired(sub_authorities.length)
128
+ sid = FFI::MemoryPointer.new(:uchar, size)
156
129
 
157
- auth = 0.chr * 5 + authority.chr
130
+ auth = SID_IDENTIFIER_AUTHORITY.new
131
+ auth[:Value][5] = authority
158
132
 
159
133
  unless InitializeSid(sid, auth, sub_authorities.length)
160
- raise Error, get_last_error
134
+ raise SystemCallError.new("InitializeSid", FFI.errno)
161
135
  end
162
136
 
163
137
  sub_authorities.each_index do |i|
164
- value = [sub_authorities[i]].pack('L')
165
- auth_ptr = GetSidSubAuthority(sid, i)
166
- memcpy(auth_ptr, value, 4)
138
+ ptr = GetSidSubAuthority(sid, i)
139
+ ptr.write_ulong(sub_authorities[i])
167
140
  end
168
141
 
169
- new(sid)
142
+ new(sid.read_string(size)) # Pass a binary string
170
143
  end
171
144
 
172
145
  # Creates and returns a new Win32::Security::SID object, based on
@@ -198,45 +171,41 @@ module Win32
198
171
  #
199
172
  def initialize(account=nil, host=Socket.gethostname)
200
173
  if account.nil?
201
- htoken = [0].pack('L')
202
- bool = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, 1, htoken)
203
- errno = GetLastError()
204
-
205
- if !bool
206
- if errno == ERROR_NO_TOKEN
207
- unless OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, htoken)
208
- raise get_last_error
209
- end
174
+ begin
175
+ ptoken = FFI::MemoryPointer.new(:ulong)
176
+
177
+ # Try the thread token first, default to the process token.
178
+ bool = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, true, ptoken)
179
+
180
+ if !bool && FFI.errno != ERROR_NO_TOKEN
181
+ raise SystemCallError.new("OpenThreadToken", FFI.errno)
210
182
  else
211
- raise get_last_error(errno)
183
+ ptoken = FFI::MemoryPointer.new(:ulong)
184
+ unless OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, ptoken)
185
+ raise SystemCallError.new("OpenProcessToken", FFI.errno)
186
+ end
212
187
  end
213
- end
214
188
 
215
- htoken = htoken.unpack('V').first
216
- cbti = [0].pack('L')
217
- token_info = 0.chr * 36
189
+ token = ptoken.read_ulong
190
+ pinfo = FFI::MemoryPointer.new(:pointer)
191
+ plength = FFI::MemoryPointer.new(:ulong)
218
192
 
219
- bool = GetTokenInformation(
220
- htoken,
221
- TokenOwner,
222
- token_info,
223
- token_info.size,
224
- cbti
225
- )
193
+ # First pass, just get the size needed (1 is TokenOwner)
194
+ GetTokenInformation(token, 1, pinfo, pinfo.size, plength)
226
195
 
227
- unless bool
228
- raise Error, get_last_error
229
- end
230
- end
196
+ pinfo = FFI::MemoryPointer.new(plength.read_ulong)
197
+ plength = FFI::MemoryPointer.new(:ulong)
231
198
 
232
- bool = false
233
- sid = 0.chr * 28
234
- sid_cb = [sid.size].pack('L')
235
-
236
- domain_buf = 0.chr * 80
237
- domain_cch = [domain_buf.size].pack('L')
199
+ # Second pass, actual call (1 is TokenOwner)
200
+ unless GetTokenInformation(token, 1, pinfo, pinfo.size, plength)
201
+ raise SystemCallError.new("GetTokenInformation", FFI.errno)
202
+ end
238
203
 
239
- sid_name_use = 0.chr * 4
204
+ token_info = pinfo.read_pointer
205
+ ensure
206
+ CloseHandle(token) if token
207
+ end
208
+ end
240
209
 
241
210
  if account
242
211
  ordinal_val = account[0]
@@ -245,61 +214,74 @@ module Win32
245
214
  ordinal_val = nil
246
215
  end
247
216
 
217
+ sid = FFI::MemoryPointer.new(:uchar, 260)
218
+ sid_size = FFI::MemoryPointer.new(:ulong)
219
+ sid_size.write_ulong(sid.size)
220
+
221
+ domain = FFI::MemoryPointer.new(:uchar, 260)
222
+ domain_size = FFI::MemoryPointer.new(:ulong)
223
+ domain_size.write_ulong(domain.size)
224
+
225
+ use_ptr = FFI::MemoryPointer.new(:ulong)
226
+
248
227
  if ordinal_val.nil?
249
228
  bool = LookupAccountSid(
250
229
  nil,
251
- token_info.unpack('L')[0],
230
+ token_info,
252
231
  sid,
253
- sid_cb,
254
- domain_buf,
255
- domain_cch,
256
- sid_name_use
232
+ sid_size,
233
+ domain,
234
+ domain_size,
235
+ use_ptr
257
236
  )
237
+ unless bool
238
+ raise SystemCallError.new("LookupAccountSid", FFI.errno)
239
+ end
258
240
  elsif ordinal_val < 10 # Assume it's a binary SID.
241
+ account_ptr = FFI::MemoryPointer.from_string(account)
259
242
  bool = LookupAccountSid(
260
243
  host,
261
- [account].pack('p*').unpack('L')[0],
244
+ account_ptr,
262
245
  sid,
263
- sid_cb,
264
- domain_buf,
265
- domain_cch,
266
- sid_name_use
246
+ sid_size,
247
+ domain,
248
+ domain_size,
249
+ use_ptr
267
250
  )
251
+ unless bool
252
+ raise SystemCallError.new("LookupAccountSid", FFI.errno)
253
+ end
268
254
  else
269
255
  bool = LookupAccountName(
270
256
  host,
271
257
  account,
272
258
  sid,
273
- sid_cb,
274
- domain_buf,
275
- domain_cch,
276
- sid_name_use
259
+ sid_size,
260
+ domain,
261
+ domain_size,
262
+ use_ptr,
277
263
  )
278
- end
279
-
280
- unless bool
281
- raise Error, get_last_error
264
+ unless bool
265
+ raise SystemCallError.new("LookupAccountName", FFI.errno)
266
+ end
282
267
  end
283
268
 
284
269
  # The arguments are flipped depending on which path we took
285
270
  if ordinal_val.nil?
286
- buf = 0.chr * 260
287
- ptr = token_info.unpack('L')[0]
288
- memcpy(buf, ptr, token_info.size)
289
- @sid = buf.strip
290
- @account = sid.strip
271
+ @sid = token_info.read_string
272
+ @account = sid.read_string(sid.size).strip
291
273
  elsif ordinal_val < 10
292
274
  @sid = account
293
- @account = sid.strip
275
+ @account = sid.read_string(sid.size).strip
294
276
  else
295
- @sid = sid.strip
277
+ @sid = sid.read_string(sid.size).strip
296
278
  @account = account
297
279
  end
298
280
 
299
281
  @host = host
300
- @domain = domain_buf.strip
282
+ @domain = domain.read_string
301
283
 
302
- @account_type = get_account_type(sid_name_use.unpack('L')[0])
284
+ @account_type = get_account_type(use_ptr.read_ulong)
303
285
  end
304
286
 
305
287
  # Synonym for SID.new.
@@ -312,16 +294,13 @@ module Win32
312
294
  # storage or transmission.
313
295
  #
314
296
  def to_s
315
- sid_addr = [@sid].pack('p*').unpack('L').first
316
- sid_buf = 0.chr * 80
317
- sid_ptr = 0.chr * 4
297
+ ptr = FFI::MemoryPointer.new(:pointer)
318
298
 
319
- unless ConvertSidToStringSid(sid_addr, sid_ptr)
320
- raise Error, get_last_error
299
+ unless ConvertSidToStringSid(@sid, ptr)
300
+ raise SystemCallError.new("ConvertSidToStringSid", FFI.errno)
321
301
  end
322
302
 
323
- strcpy(sid_buf, sid_ptr.unpack('L').first)
324
- sid_buf.strip
303
+ ptr.read_pointer.read_string
325
304
  end
326
305
 
327
306
  alias to_str to_s