win32-security 0.1.3 → 0.1.4

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