win32-security 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,394 +1,394 @@
1
- require 'socket'
2
-
3
- # The Win32 module serves as a namespace only.
4
- module Win32
5
-
6
- # The Security class serves as a toplevel class namespace.
7
- class Security
8
-
9
- # The SID class encapsulates a Security Identifier.
10
- class SID
11
- include Windows::Security::Constants
12
- include Windows::Security::Functions
13
- include Windows::Security::Structs
14
- extend Windows::Security::Functions
15
-
16
- # The version of the Win32::Security::SID class.
17
- VERSION = '0.2.1'
18
-
19
- # Some constant SID's for your convenience, in string format.
20
- # See http://support.microsoft.com/kb/243330 for details.
21
-
22
- Null = 'S-1-0'
23
- Nobody = 'S-1-0-0'
24
- World = 'S-1-1'
25
- Everyone = 'S-1-1-0'
26
- Local = 'S-1-2'
27
- Creator = 'S-1-3'
28
- CreatorOwner = 'S-1-3-0'
29
- CreatorGroup = 'S-1-3-1'
30
- CreatorOwnerServer = 'S-1-3-2'
31
- CreatorGroupServer = 'S-1-3-3'
32
- NonUnique = 'S-1-4'
33
- Nt = 'S-1-5'
34
- Dialup = 'S-1-5-1'
35
- Network = 'S-1-5-2'
36
- Batch = 'S-1-5-3'
37
- Interactive = 'S-1-5-4'
38
- Service = 'S-1-5-6'
39
- Anonymous = 'S-1-5-7'
40
- Proxy = 'S-1-5-8'
41
- EnterpriseDomainControllers = 'S-1-5-9'
42
- PrincipalSelf = 'S-1-5-10'
43
- AuthenticatedUsers = 'S-1-5-11'
44
- RestrictedCode = 'S-1-5-12'
45
- TerminalServerUsers = 'S-1-5-13'
46
- LocalSystem = 'S-1-5-18'
47
- NtLocal = 'S-1-5-19'
48
- NtNetwork = 'S-1-5-20'
49
- BuiltinAdministrators = 'S-1-5-32-544'
50
- BuiltinUsers = 'S-1-5-32-545'
51
- Guests = 'S-1-5-32-546'
52
- PowerUsers = 'S-1-5-32-547'
53
- AccountOperators = 'S-1-5-32-548'
54
- ServerOperators = 'S-1-5-32-549'
55
- PrintOperators = 'S-1-5-32-550'
56
- BackupOperators = 'S-1-5-32-551'
57
- Replicators = 'S-1-5-32-552'
58
-
59
- # The binary SID object itself.
60
- attr_reader :sid
61
-
62
- # The account name passed to the constructor.
63
- attr_reader :account
64
-
65
- # The SID account type, e.g. 'user, 'group', etc.
66
- attr_reader :account_type
67
-
68
- # The domain the SID is on.
69
- attr_reader :domain
70
-
71
- # The host passed to the constructor, or the localhost if none
72
- # was specified.
73
- attr_reader :host
74
-
75
- # Converts a binary SID to a string in S-R-I-S-S... format.
76
- #
77
- def self.sid_to_string(sid)
78
- result = nil
79
-
80
- FFI::MemoryPointer.new(:pointer) do |string_sid|
81
- unless ConvertSidToStringSid(sid, string_sid)
82
- raise SystemCallError.new("ConvertSidToStringSid", FFI.errno)
83
- end
84
-
85
- result = string_sid.read_pointer.read_string
86
- end
87
-
88
- result
89
- end
90
-
91
- # Converts a string in S-R-I-S-S... format back to a binary SID.
92
- #
93
- def self.string_to_sid(string)
94
- result = nil
95
-
96
- FFI::MemoryPointer.new(:pointer) do |sid|
97
- unless ConvertStringSidToSid(string, sid)
98
- raise SystemCallError.new("ConvertStringSidToSid", FFI.errno)
99
- end
100
-
101
- ptr = sid.read_pointer
102
-
103
- result = ptr.read_bytes(GetLengthSid(ptr))
104
- end
105
-
106
- result
107
- end
108
-
109
- # Creates a new SID with +authority+ and up to 8 +subauthorities+,
110
- # and returns new Win32::Security::SID object.
111
- #
112
- # Example:
113
- #
114
- # sec = Security::SID.create(
115
- # Security::SID::SECURITY_WORLD_SID_AUTHORITY,
116
- # Security::SID::SECURITY_WORLD_RID
117
- # )
118
- #
119
- # p sec
120
- #
121
- # #<Win32::Security::SID:0x2c5a95c
122
- # @host="your_host",
123
- # @account="Everyone",
124
- # @account_type="well known group",
125
- # @sid="\001\001\000\000\000\000\000\001\000\000\000\000",
126
- # @domain=""
127
- # >
128
- #
129
- def self.create(authority, *sub_authorities)
130
- if sub_authorities.length > 8
131
- raise ArgumentError, "maximum of 8 subauthorities allowed"
132
- end
133
-
134
- size = GetSidLengthRequired(sub_authorities.length)
135
- new_obj = nil
136
-
137
- FFI::MemoryPointer.new(:uchar, size) do |sid|
138
- auth = SID_IDENTIFIER_AUTHORITY.new
139
- auth[:Value][5] = authority
140
-
141
- unless InitializeSid(sid, auth, sub_authorities.length)
142
- raise SystemCallError.new("InitializeSid", FFI.errno)
143
- end
144
-
145
- sub_authorities.each_index do |i|
146
- ptr = GetSidSubAuthority(sid, i)
147
- ptr.write_ulong(sub_authorities[i])
148
- end
149
-
150
- new_obj = new(sid.read_string(size)) # Pass a binary string
151
- end
152
-
153
- new_obj
154
- end
155
-
156
- # Creates and returns a new Win32::Security::SID object, based on
157
- # the account name, which may also be a binary SID. If a host is
158
- # provided, then the information is retrieved from that host.
159
- # Otherwise, the local host is used.
160
- #
161
- # If no account is provided then it retrieves information for the
162
- # user account associated with the calling thread and the host argument
163
- # is ignored.
164
- #
165
- # Note that this does NOT create a new SID, but merely retrieves
166
- # information for an existing SID. To create a new SID, use the
167
- # SID.create method.
168
- #
169
- # Examples:
170
- #
171
- # # Current user
172
- # Win32::Security::SID.new
173
- #
174
- # # User 'john' on the localhost
175
- # Win32::Security::SID.new('john')
176
- #
177
- # # User 'jane' on a remote machine
178
- # Win32::Security::SID.new('jane', 'some_host')
179
- #
180
- # # Binary SID
181
- # Win32::Security::SID.new("\001\000\000\000\000\000\001\000\000\000\000")
182
- #
183
- def initialize(account=nil, host=Socket.gethostname)
184
- if account.nil?
185
- begin
186
- if RUBY_PLATFORM == 'java' && ENV_JAVA['sun.arch.data.model'] == '64'
187
- ptr_type = :ulong_long
188
- else
189
- ptr_type = :uintptr_t
190
- end
191
-
192
- ptoken = FFI::MemoryPointer.new(ptr_type)
193
-
194
- # Try the thread token first, default to the process token.
195
- bool = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, true, ptoken)
196
-
197
- if !bool && FFI.errno != ERROR_NO_TOKEN
198
- raise SystemCallError.new("OpenThreadToken", FFI.errno)
199
- else
200
- ptoken.clear
201
- unless OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, ptoken)
202
- raise SystemCallError.new("OpenProcessToken", FFI.errno)
203
- end
204
- end
205
-
206
- token = ptoken.read_pointer.to_i
207
-
208
- pinfo = FFI::MemoryPointer.new(:pointer)
209
- plength = FFI::MemoryPointer.new(:ulong)
210
-
211
- # First pass, just get the size needed (1 is TokenOwner)
212
- GetTokenInformation(token, 1, pinfo, pinfo.size, plength)
213
-
214
- pinfo = FFI::MemoryPointer.new(plength.read_ulong)
215
- plength.clear
216
-
217
- # Second pass, actual call (1 is TokenOwner)
218
- unless GetTokenInformation(token, 1, pinfo, pinfo.size, plength)
219
- raise SystemCallError.new("GetTokenInformation", FFI.errno)
220
- end
221
-
222
- token_info = pinfo.read_pointer
223
- ensure
224
- CloseHandle(token) if token
225
- end
226
- end
227
-
228
- if account
229
- ordinal_val = account[0]
230
- ordinal_val = ordinal_val.ord if RUBY_VERSION.to_f >= 1.9
231
- else
232
- ordinal_val = nil
233
- end
234
-
235
- sid = FFI::MemoryPointer.new(:uchar, 260)
236
- sid_size = FFI::MemoryPointer.new(:ulong)
237
- sid_size.write_ulong(sid.size)
238
-
239
- domain = FFI::MemoryPointer.new(:uchar, 260)
240
- domain_size = FFI::MemoryPointer.new(:ulong)
241
- domain_size.write_ulong(domain.size)
242
-
243
- use_ptr = FFI::MemoryPointer.new(:ulong)
244
-
245
- if ordinal_val.nil?
246
- bool = LookupAccountSid(
247
- nil,
248
- token_info,
249
- sid,
250
- sid_size,
251
- domain,
252
- domain_size,
253
- use_ptr
254
- )
255
- unless bool
256
- raise SystemCallError.new("LookupAccountSid", FFI.errno)
257
- end
258
- elsif ordinal_val < 10 # Assume it's a binary SID.
259
- account_ptr = FFI::MemoryPointer.from_string(account)
260
-
261
- bool = LookupAccountSid(
262
- host,
263
- account_ptr,
264
- sid,
265
- sid_size,
266
- domain,
267
- domain_size,
268
- use_ptr
269
- )
270
-
271
- unless bool
272
- raise SystemCallError.new("LookupAccountSid", FFI.errno)
273
- end
274
-
275
- account_ptr.free
276
- else
277
- bool = LookupAccountName(
278
- host,
279
- account,
280
- sid,
281
- sid_size,
282
- domain,
283
- domain_size,
284
- use_ptr
285
- )
286
- unless bool
287
- raise SystemCallError.new("LookupAccountName", FFI.errno)
288
- end
289
- end
290
-
291
- # The arguments are flipped depending on which path we took
292
- if ordinal_val.nil?
293
- @sid = token_info.read_string
294
- @account = sid.read_string(sid.size).strip
295
- elsif ordinal_val < 10
296
- @sid = account
297
- @account = sid.read_string(sid.size).strip
298
- else
299
- length = GetLengthSid(sid)
300
- @sid = sid.read_string(length)
301
- @account = account
302
- end
303
-
304
- @host = host
305
- @domain = domain.read_string
306
-
307
- @account_type = get_account_type(use_ptr.read_ulong)
308
- end
309
-
310
- # Synonym for SID.new.
311
- #
312
- def self.open(account=nil, host=Socket.gethostname)
313
- new(account, host)
314
- end
315
-
316
- # Returns the binary SID in string format suitable for display,
317
- # storage or transmission.
318
- #
319
- def to_s
320
- string = nil
321
-
322
- FFI::MemoryPointer.new(:pointer) do |ptr|
323
- unless ConvertSidToStringSid(@sid, ptr)
324
- raise SystemCallError.new("ConvertSidToStringSid", FFI.errno)
325
- end
326
-
327
- string = ptr.read_pointer.read_string
328
- end
329
-
330
- string
331
- end
332
-
333
- alias to_str to_s
334
-
335
- # Returns whether or not the SID object is equal to +other+.
336
- #
337
- def ==(other)
338
- EqualSid(@sid, other.sid)
339
- end
340
-
341
- # Returns whether or not the SID is a valid sid.
342
- #
343
- def valid?
344
- IsValidSid(@sid)
345
- end
346
-
347
- # Returns whether or not the SID is a well known SID.
348
- #
349
- # Requires Windows XP or later. Earlier versions will raise a
350
- # NoMethodError.
351
- #
352
- def well_known?
353
- if defined? IsWellKnownSid
354
- IsWellKnownSid(@sid)
355
- else
356
- raise NoMethodError, 'requires Windows XP or later'
357
- end
358
- end
359
-
360
- # Returns the length of the SID object, in bytes.
361
- #
362
- def length
363
- GetLengthSid(@sid)
364
- end
365
-
366
- private
367
-
368
- # Converts a numeric account type into a human readable string.
369
- #
370
- def get_account_type(value)
371
- case value
372
- when SidTypeUser
373
- 'user'
374
- when SidTypeGroup
375
- 'group'
376
- when SidTypeDomain
377
- 'domain'
378
- when SidTypeAlias
379
- 'alias'
380
- when SidTypeWellKnownGroup
381
- 'well known group'
382
- when SidTypeDeletedAccount
383
- 'deleted account'
384
- when SidTypeInvalid
385
- 'invalid'
386
- when SidTypeUnknown
387
- 'unknown'
388
- when SidComputer
389
- 'computer'
390
- end
391
- end
392
- end
393
- end
394
- end
1
+ require 'socket'
2
+
3
+ # The Win32 module serves as a namespace only.
4
+ module Win32
5
+
6
+ # The Security class serves as a toplevel class namespace.
7
+ class Security
8
+
9
+ # The SID class encapsulates a Security Identifier.
10
+ class SID
11
+ include Windows::Security::Constants
12
+ include Windows::Security::Functions
13
+ include Windows::Security::Structs
14
+ extend Windows::Security::Functions
15
+
16
+ # The version of the Win32::Security::SID class.
17
+ VERSION = '0.2.2'
18
+
19
+ # Some constant SID's for your convenience, in string format.
20
+ # See http://support.microsoft.com/kb/243330 for details.
21
+
22
+ Null = 'S-1-0'
23
+ Nobody = 'S-1-0-0'
24
+ World = 'S-1-1'
25
+ Everyone = 'S-1-1-0'
26
+ Local = 'S-1-2'
27
+ Creator = 'S-1-3'
28
+ CreatorOwner = 'S-1-3-0'
29
+ CreatorGroup = 'S-1-3-1'
30
+ CreatorOwnerServer = 'S-1-3-2'
31
+ CreatorGroupServer = 'S-1-3-3'
32
+ NonUnique = 'S-1-4'
33
+ Nt = 'S-1-5'
34
+ Dialup = 'S-1-5-1'
35
+ Network = 'S-1-5-2'
36
+ Batch = 'S-1-5-3'
37
+ Interactive = 'S-1-5-4'
38
+ Service = 'S-1-5-6'
39
+ Anonymous = 'S-1-5-7'
40
+ Proxy = 'S-1-5-8'
41
+ EnterpriseDomainControllers = 'S-1-5-9'
42
+ PrincipalSelf = 'S-1-5-10'
43
+ AuthenticatedUsers = 'S-1-5-11'
44
+ RestrictedCode = 'S-1-5-12'
45
+ TerminalServerUsers = 'S-1-5-13'
46
+ LocalSystem = 'S-1-5-18'
47
+ NtLocal = 'S-1-5-19'
48
+ NtNetwork = 'S-1-5-20'
49
+ BuiltinAdministrators = 'S-1-5-32-544'
50
+ BuiltinUsers = 'S-1-5-32-545'
51
+ Guests = 'S-1-5-32-546'
52
+ PowerUsers = 'S-1-5-32-547'
53
+ AccountOperators = 'S-1-5-32-548'
54
+ ServerOperators = 'S-1-5-32-549'
55
+ PrintOperators = 'S-1-5-32-550'
56
+ BackupOperators = 'S-1-5-32-551'
57
+ Replicators = 'S-1-5-32-552'
58
+
59
+ # The binary SID object itself.
60
+ attr_reader :sid
61
+
62
+ # The account name passed to the constructor.
63
+ attr_reader :account
64
+
65
+ # The SID account type, e.g. 'user, 'group', etc.
66
+ attr_reader :account_type
67
+
68
+ # The domain the SID is on.
69
+ attr_reader :domain
70
+
71
+ # The host passed to the constructor, or the localhost if none
72
+ # was specified.
73
+ attr_reader :host
74
+
75
+ # Converts a binary SID to a string in S-R-I-S-S... format.
76
+ #
77
+ def self.sid_to_string(sid)
78
+ result = nil
79
+
80
+ FFI::MemoryPointer.new(:pointer) do |string_sid|
81
+ unless ConvertSidToStringSid(sid, string_sid)
82
+ raise SystemCallError.new("ConvertSidToStringSid", FFI.errno)
83
+ end
84
+
85
+ result = string_sid.read_pointer.read_string
86
+ end
87
+
88
+ result
89
+ end
90
+
91
+ # Converts a string in S-R-I-S-S... format back to a binary SID.
92
+ #
93
+ def self.string_to_sid(string)
94
+ result = nil
95
+
96
+ FFI::MemoryPointer.new(:pointer) do |sid|
97
+ unless ConvertStringSidToSid(string, sid)
98
+ raise SystemCallError.new("ConvertStringSidToSid", FFI.errno)
99
+ end
100
+
101
+ ptr = sid.read_pointer
102
+
103
+ result = ptr.read_bytes(GetLengthSid(ptr))
104
+ end
105
+
106
+ result
107
+ end
108
+
109
+ # Creates a new SID with +authority+ and up to 8 +subauthorities+,
110
+ # and returns new Win32::Security::SID object.
111
+ #
112
+ # Example:
113
+ #
114
+ # sec = Security::SID.create(
115
+ # Security::SID::SECURITY_WORLD_SID_AUTHORITY,
116
+ # Security::SID::SECURITY_WORLD_RID
117
+ # )
118
+ #
119
+ # p sec
120
+ #
121
+ # #<Win32::Security::SID:0x2c5a95c
122
+ # @host="your_host",
123
+ # @account="Everyone",
124
+ # @account_type="well known group",
125
+ # @sid="\001\001\000\000\000\000\000\001\000\000\000\000",
126
+ # @domain=""
127
+ # >
128
+ #
129
+ def self.create(authority, *sub_authorities)
130
+ if sub_authorities.length > 8
131
+ raise ArgumentError, "maximum of 8 subauthorities allowed"
132
+ end
133
+
134
+ size = GetSidLengthRequired(sub_authorities.length)
135
+ new_obj = nil
136
+
137
+ FFI::MemoryPointer.new(:uchar, size) do |sid|
138
+ auth = SID_IDENTIFIER_AUTHORITY.new
139
+ auth[:Value][5] = authority
140
+
141
+ unless InitializeSid(sid, auth, sub_authorities.length)
142
+ raise SystemCallError.new("InitializeSid", FFI.errno)
143
+ end
144
+
145
+ sub_authorities.each_index do |i|
146
+ ptr = GetSidSubAuthority(sid, i)
147
+ ptr.write_ulong(sub_authorities[i])
148
+ end
149
+
150
+ new_obj = new(sid.read_string(size)) # Pass a binary string
151
+ end
152
+
153
+ new_obj
154
+ end
155
+
156
+ # Creates and returns a new Win32::Security::SID object, based on
157
+ # the account name, which may also be a binary SID. If a host is
158
+ # provided, then the information is retrieved from that host.
159
+ # Otherwise, the local host is used.
160
+ #
161
+ # If no account is provided then it retrieves information for the
162
+ # user account associated with the calling thread and the host argument
163
+ # is ignored.
164
+ #
165
+ # Note that this does NOT create a new SID, but merely retrieves
166
+ # information for an existing SID. To create a new SID, use the
167
+ # SID.create method.
168
+ #
169
+ # Examples:
170
+ #
171
+ # # Current user
172
+ # Win32::Security::SID.new
173
+ #
174
+ # # User 'john' on the localhost
175
+ # Win32::Security::SID.new('john')
176
+ #
177
+ # # User 'jane' on a remote machine
178
+ # Win32::Security::SID.new('jane', 'some_host')
179
+ #
180
+ # # Binary SID
181
+ # Win32::Security::SID.new("\001\000\000\000\000\000\001\000\000\000\000")
182
+ #
183
+ def initialize(account=nil, host=Socket.gethostname)
184
+ if account.nil?
185
+ begin
186
+ if RUBY_PLATFORM == 'java' && ENV_JAVA['sun.arch.data.model'] == '64'
187
+ ptr_type = :ulong_long
188
+ else
189
+ ptr_type = :uintptr_t
190
+ end
191
+
192
+ ptoken = FFI::MemoryPointer.new(ptr_type)
193
+
194
+ # Try the thread token first, default to the process token.
195
+ bool = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, 1, ptoken)
196
+
197
+ if !bool && FFI.errno != ERROR_NO_TOKEN
198
+ raise SystemCallError.new("OpenThreadToken", FFI.errno)
199
+ else
200
+ ptoken.clear
201
+ unless OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, ptoken)
202
+ raise SystemCallError.new("OpenProcessToken", FFI.errno)
203
+ end
204
+ end
205
+
206
+ token = ptoken.read_pointer.to_i
207
+
208
+ pinfo = FFI::MemoryPointer.new(:pointer)
209
+ plength = FFI::MemoryPointer.new(:ulong)
210
+
211
+ # First pass, just get the size needed (1 is TokenOwner)
212
+ GetTokenInformation(token, 1, pinfo, pinfo.size, plength)
213
+
214
+ pinfo = FFI::MemoryPointer.new(plength.read_ulong)
215
+ plength.clear
216
+
217
+ # Second pass, actual call (1 is TokenOwner)
218
+ unless GetTokenInformation(token, 1, pinfo, pinfo.size, plength)
219
+ raise SystemCallError.new("GetTokenInformation", FFI.errno)
220
+ end
221
+
222
+ token_info = pinfo.read_pointer
223
+ ensure
224
+ CloseHandle(token) if token
225
+ end
226
+ end
227
+
228
+ if account
229
+ ordinal_val = account[0]
230
+ ordinal_val = ordinal_val.ord if RUBY_VERSION.to_f >= 1.9
231
+ else
232
+ ordinal_val = nil
233
+ end
234
+
235
+ sid = FFI::MemoryPointer.new(:uchar, 260)
236
+ sid_size = FFI::MemoryPointer.new(:ulong)
237
+ sid_size.write_ulong(sid.size)
238
+
239
+ domain = FFI::MemoryPointer.new(:uchar, 260)
240
+ domain_size = FFI::MemoryPointer.new(:ulong)
241
+ domain_size.write_ulong(domain.size)
242
+
243
+ use_ptr = FFI::MemoryPointer.new(:ulong)
244
+
245
+ if ordinal_val.nil?
246
+ bool = LookupAccountSid(
247
+ nil,
248
+ token_info,
249
+ sid,
250
+ sid_size,
251
+ domain,
252
+ domain_size,
253
+ use_ptr
254
+ )
255
+ unless bool
256
+ raise SystemCallError.new("LookupAccountSid", FFI.errno)
257
+ end
258
+ elsif ordinal_val < 10 # Assume it's a binary SID.
259
+ account_ptr = FFI::MemoryPointer.from_string(account)
260
+
261
+ bool = LookupAccountSid(
262
+ host,
263
+ account_ptr,
264
+ sid,
265
+ sid_size,
266
+ domain,
267
+ domain_size,
268
+ use_ptr
269
+ )
270
+
271
+ unless bool
272
+ raise SystemCallError.new("LookupAccountSid", FFI.errno)
273
+ end
274
+
275
+ account_ptr.free
276
+ else
277
+ bool = LookupAccountName(
278
+ host,
279
+ account,
280
+ sid,
281
+ sid_size,
282
+ domain,
283
+ domain_size,
284
+ use_ptr
285
+ )
286
+ unless bool
287
+ raise SystemCallError.new("LookupAccountName", FFI.errno)
288
+ end
289
+ end
290
+
291
+ # The arguments are flipped depending on which path we took
292
+ if ordinal_val.nil?
293
+ @sid = token_info.read_string
294
+ @account = sid.read_string(sid.size).strip
295
+ elsif ordinal_val < 10
296
+ @sid = account
297
+ @account = sid.read_string(sid.size).strip
298
+ else
299
+ length = GetLengthSid(sid)
300
+ @sid = sid.read_string(length)
301
+ @account = account
302
+ end
303
+
304
+ @host = host
305
+ @domain = domain.read_string
306
+
307
+ @account_type = get_account_type(use_ptr.read_ulong)
308
+ end
309
+
310
+ # Synonym for SID.new.
311
+ #
312
+ def self.open(account=nil, host=Socket.gethostname)
313
+ new(account, host)
314
+ end
315
+
316
+ # Returns the binary SID in string format suitable for display,
317
+ # storage or transmission.
318
+ #
319
+ def to_s
320
+ string = nil
321
+
322
+ FFI::MemoryPointer.new(:pointer) do |ptr|
323
+ unless ConvertSidToStringSid(@sid, ptr)
324
+ raise SystemCallError.new("ConvertSidToStringSid", FFI.errno)
325
+ end
326
+
327
+ string = ptr.read_pointer.read_string
328
+ end
329
+
330
+ string
331
+ end
332
+
333
+ alias to_str to_s
334
+
335
+ # Returns whether or not the SID object is equal to +other+.
336
+ #
337
+ def ==(other)
338
+ EqualSid(@sid, other.sid)
339
+ end
340
+
341
+ # Returns whether or not the SID is a valid sid.
342
+ #
343
+ def valid?
344
+ IsValidSid(@sid)
345
+ end
346
+
347
+ # Returns whether or not the SID is a well known SID.
348
+ #
349
+ # Requires Windows XP or later. Earlier versions will raise a
350
+ # NoMethodError.
351
+ #
352
+ def well_known?
353
+ if defined? IsWellKnownSid
354
+ IsWellKnownSid(@sid)
355
+ else
356
+ raise NoMethodError, 'requires Windows XP or later'
357
+ end
358
+ end
359
+
360
+ # Returns the length of the SID object, in bytes.
361
+ #
362
+ def length
363
+ GetLengthSid(@sid)
364
+ end
365
+
366
+ private
367
+
368
+ # Converts a numeric account type into a human readable string.
369
+ #
370
+ def get_account_type(value)
371
+ case value
372
+ when SidTypeUser
373
+ 'user'
374
+ when SidTypeGroup
375
+ 'group'
376
+ when SidTypeDomain
377
+ 'domain'
378
+ when SidTypeAlias
379
+ 'alias'
380
+ when SidTypeWellKnownGroup
381
+ 'well known group'
382
+ when SidTypeDeletedAccount
383
+ 'deleted account'
384
+ when SidTypeInvalid
385
+ 'invalid'
386
+ when SidTypeUnknown
387
+ 'unknown'
388
+ when SidComputer
389
+ 'computer'
390
+ end
391
+ end
392
+ end
393
+ end
394
+ end