win32-security 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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