win32-security 0.1.0 → 0.1.1
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 +7 -1
- data/lib/win32/security.rb +1 -1
- data/lib/win32/security/sid.rb +311 -0
- data/test/test_acl.rb +67 -0
- data/test/test_security.rb +1 -1
- data/test/test_sid.rb +11 -1
- data/win32-security.gemspec +25 -26
- metadata +14 -11
data/CHANGES
CHANGED
@@ -1,2 +1,8 @@
|
|
1
|
+
= 0.1.1 - 14-Jul-2009
|
2
|
+
* Added some well known SID's as constants to the Win32::Security::SID class
|
3
|
+
for convenience, e.g. SID::World, SID::Everyone.
|
4
|
+
* Fixes for the gemspec.
|
5
|
+
* Changed license to Artistic 2.0.
|
6
|
+
|
1
7
|
= 0.1.0 - 17-Dec-2008
|
2
|
-
* Initial release
|
8
|
+
* Initial release
|
data/lib/win32/security.rb
CHANGED
@@ -0,0 +1,311 @@
|
|
1
|
+
require 'windows/security'
|
2
|
+
require 'windows/error'
|
3
|
+
require 'windows/msvcrt/string'
|
4
|
+
require 'windows/msvcrt/buffer'
|
5
|
+
require 'socket'
|
6
|
+
|
7
|
+
# The Win32 module serves as a namespace only.
|
8
|
+
module Win32
|
9
|
+
|
10
|
+
# The Security class serves as a toplevel class namespace.
|
11
|
+
class Security
|
12
|
+
|
13
|
+
# The SID class encapsulates a Security Identifier.
|
14
|
+
class SID
|
15
|
+
include Windows::Security
|
16
|
+
include Windows::Error
|
17
|
+
include Windows::MSVCRT::String
|
18
|
+
|
19
|
+
extend Windows::Security
|
20
|
+
extend Windows::Error
|
21
|
+
extend Windows::MSVCRT::String
|
22
|
+
extend Windows::MSVCRT::Buffer
|
23
|
+
|
24
|
+
# Error class typically raised if any of the SID methods fail
|
25
|
+
class Error < StandardError; end
|
26
|
+
|
27
|
+
# The version of the Win32::Security::SID class.
|
28
|
+
VERSION = '0.1.1'
|
29
|
+
|
30
|
+
# Some constant SID's for your convenience, in string format.
|
31
|
+
# See http://support.microsoft.com/kb/243330 for details.
|
32
|
+
|
33
|
+
Null = 'S-1-0'
|
34
|
+
Nobody = 'S-1-0-0'
|
35
|
+
World = 'S-1-1'
|
36
|
+
Everyone = 'S-1-1-0'
|
37
|
+
Local = 'S-1-2'
|
38
|
+
Creator = 'S-1-3'
|
39
|
+
CreatorOwner = 'S-1-3-0'
|
40
|
+
CreatorGroup = 'S-1-3-1'
|
41
|
+
CreatorOwnerServer = 'S-1-3-2'
|
42
|
+
CreatorGroupServer = 'S-1-3-3'
|
43
|
+
NonUnique = 'S-1-4'
|
44
|
+
Nt = 'S-1-5'
|
45
|
+
Dialup = 'S-1-5-1'
|
46
|
+
Network = 'S-1-5-2'
|
47
|
+
Batch = 'S-1-5-3'
|
48
|
+
Interactive = 'S-1-5-4'
|
49
|
+
Service = 'S-1-5-6'
|
50
|
+
Anonymous = 'S-1-5-7'
|
51
|
+
Proxy = 'S-1-5-8'
|
52
|
+
EnterpriseDomainControllers = 'S-1-5-9'
|
53
|
+
PrincipalSelf = 'S-1-5-10'
|
54
|
+
AuthenticatedUsers = 'S-1-5-11'
|
55
|
+
RestrictedCode = 'S-1-5-12'
|
56
|
+
TerminalServerUsers = 'S-1-5-13'
|
57
|
+
LocalSystem = 'S-1-5-18'
|
58
|
+
NtLocal = 'S-1-5-19'
|
59
|
+
NtNetwork = 'S-1-5-20'
|
60
|
+
BuiltinAdministrators = 'S-1-5-32-544'
|
61
|
+
BuiltinUsers = 'S-1-5-32-545'
|
62
|
+
Guests = 'S-1-5-32-546'
|
63
|
+
PowerUsers = 'S-1-5-32-547'
|
64
|
+
AccountOperators = 'S-1-5-32-548'
|
65
|
+
ServerOperators = 'S-1-5-32-549'
|
66
|
+
PrintOperators = 'S-1-5-32-550'
|
67
|
+
BackupOperators = 'S-1-5-32-551'
|
68
|
+
Replicators = 'S-1-5-32-552'
|
69
|
+
|
70
|
+
# The binary SID object itself.
|
71
|
+
attr_reader :sid
|
72
|
+
|
73
|
+
# The account name passed to the constructor.
|
74
|
+
attr_reader :account
|
75
|
+
|
76
|
+
# The SID account type, e.g. 'user, 'group', etc.
|
77
|
+
attr_reader :account_type
|
78
|
+
|
79
|
+
# The domain the SID is on.
|
80
|
+
attr_reader :domain
|
81
|
+
|
82
|
+
# The host passed to the constructor, or the localhost if none
|
83
|
+
# was specified.
|
84
|
+
attr_reader :host
|
85
|
+
|
86
|
+
# Converts a binary SID to a string in S-R-I-S-S... format.
|
87
|
+
#
|
88
|
+
def self.sid_to_string(sid)
|
89
|
+
sid_addr = [sid].pack('p*').unpack('L')[0]
|
90
|
+
sid_buf = 0.chr * 80
|
91
|
+
sid_ptr = 0.chr * 4
|
92
|
+
|
93
|
+
unless ConvertSidToStringSid(sid_addr, sid_ptr)
|
94
|
+
raise Error, get_last_error
|
95
|
+
end
|
96
|
+
|
97
|
+
strcpy(sid_buf, sid_ptr.unpack('L')[0])
|
98
|
+
sid_buf.strip
|
99
|
+
end
|
100
|
+
|
101
|
+
# Converts a string in S-R-I-S-S... format back to a binary SID.
|
102
|
+
#
|
103
|
+
def self.string_to_sid(string)
|
104
|
+
sid_buf = 0.chr * 80
|
105
|
+
string_addr = [string].pack('p*').unpack('L')[0]
|
106
|
+
|
107
|
+
unless ConvertStringSidToSid(string_addr, sid_buf)
|
108
|
+
raise Error, get_last_error
|
109
|
+
end
|
110
|
+
|
111
|
+
sid_buf.strip
|
112
|
+
end
|
113
|
+
|
114
|
+
# Creates a new SID with +authority+ and up to 8 +subauthorities+,
|
115
|
+
# and returns new Win32::Security::SID object.
|
116
|
+
#
|
117
|
+
# Example:
|
118
|
+
#
|
119
|
+
# sec = Security::SID.create(
|
120
|
+
# Security::SID::SECURITY_WORLD_SID_AUTHORITY,
|
121
|
+
# Security::SID::SECURITY_WORLD_RID
|
122
|
+
# )
|
123
|
+
#
|
124
|
+
# p sec
|
125
|
+
#
|
126
|
+
# #<Win32::Security::SID:0x2c5a95c
|
127
|
+
# @host="your_host",
|
128
|
+
# @account="Everyone",
|
129
|
+
# @account_type="well known group",
|
130
|
+
# @sid="\001\001\000\000\000\000\000\001\000\000\000\000",
|
131
|
+
# @domain=""
|
132
|
+
# >
|
133
|
+
#
|
134
|
+
def self.create(authority, *sub_authorities)
|
135
|
+
if sub_authorities.length > 8
|
136
|
+
raise ArgumentError, "maximum of 8 subauthorities allowed"
|
137
|
+
end
|
138
|
+
|
139
|
+
sid = 0.chr * GetSidLengthRequired(sub_authorities.length)
|
140
|
+
|
141
|
+
auth = 0.chr * 5 + authority.chr
|
142
|
+
|
143
|
+
unless InitializeSid(sid, auth, sub_authorities.length)
|
144
|
+
raise Error, get_last_error
|
145
|
+
end
|
146
|
+
|
147
|
+
sub_authorities.each_index do |i|
|
148
|
+
value = [sub_authorities[i]].pack('L')
|
149
|
+
auth_ptr = GetSidSubAuthority(sid, i)
|
150
|
+
memcpy(auth_ptr, value, 4)
|
151
|
+
end
|
152
|
+
|
153
|
+
new(sid)
|
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
|
+
# Note that this does NOT create a new SID, but merely retrieves
|
162
|
+
# information for an existing SID. To create a new SID, use the
|
163
|
+
# SID.create method.
|
164
|
+
#
|
165
|
+
# Examples:
|
166
|
+
#
|
167
|
+
# # User 'john' on the localhost
|
168
|
+
# Win32::Security::SID.new('john')
|
169
|
+
#
|
170
|
+
# # User 'jane' on a remote machine
|
171
|
+
# Win32::Security::SID.new('jane', 'some_host')
|
172
|
+
#
|
173
|
+
# # Binary SID
|
174
|
+
# Win32::Security::SID.new("\001\000\000\000\000\000\001\000\000\000\000")
|
175
|
+
#
|
176
|
+
def initialize(account, host=Socket.gethostname)
|
177
|
+
bool = false
|
178
|
+
sid = 0.chr * 28
|
179
|
+
sid_cb = [sid.size].pack('L')
|
180
|
+
|
181
|
+
domain_buf = 0.chr * 80
|
182
|
+
domain_cch = [domain_buf.size].pack('L')
|
183
|
+
|
184
|
+
sid_name_use = 0.chr * 4
|
185
|
+
|
186
|
+
# If characters in the 0-10 range, assume it's a binary SID.
|
187
|
+
if account[0] < 10
|
188
|
+
bool = LookupAccountSid(
|
189
|
+
host,
|
190
|
+
[account].pack('p*').unpack('L')[0],
|
191
|
+
sid,
|
192
|
+
sid_cb,
|
193
|
+
domain_buf,
|
194
|
+
domain_cch,
|
195
|
+
sid_name_use
|
196
|
+
)
|
197
|
+
else
|
198
|
+
bool = LookupAccountName(
|
199
|
+
host,
|
200
|
+
account,
|
201
|
+
sid,
|
202
|
+
sid_cb,
|
203
|
+
domain_buf,
|
204
|
+
domain_cch,
|
205
|
+
sid_name_use
|
206
|
+
)
|
207
|
+
end
|
208
|
+
|
209
|
+
unless bool
|
210
|
+
raise Error, get_last_error
|
211
|
+
end
|
212
|
+
|
213
|
+
# The arguments are flipped if the account argument is binary
|
214
|
+
if account[0] < 10
|
215
|
+
@sid = account
|
216
|
+
@account = sid.strip
|
217
|
+
else
|
218
|
+
@sid = sid.strip
|
219
|
+
@account = account
|
220
|
+
end
|
221
|
+
|
222
|
+
@host = host
|
223
|
+
@domain = domain_buf.strip
|
224
|
+
|
225
|
+
@account_type = get_account_type(sid_name_use.unpack('L')[0])
|
226
|
+
end
|
227
|
+
|
228
|
+
# Synonym for SID.new.
|
229
|
+
#
|
230
|
+
def self.open(account, host=Socket.gethostname)
|
231
|
+
new(account, host)
|
232
|
+
end
|
233
|
+
|
234
|
+
# Returns the binary SID in string format suitable for display,
|
235
|
+
# storage or transmission.
|
236
|
+
#
|
237
|
+
def to_s
|
238
|
+
sid_addr = [@sid].pack('p*').unpack('L').first
|
239
|
+
sid_buf = 0.chr * 80
|
240
|
+
sid_ptr = 0.chr * 4
|
241
|
+
|
242
|
+
unless ConvertSidToStringSid(sid_addr, sid_ptr)
|
243
|
+
raise Error, get_last_error
|
244
|
+
end
|
245
|
+
|
246
|
+
strcpy(sid_buf, sid_ptr.unpack('L').first)
|
247
|
+
sid_buf.strip
|
248
|
+
end
|
249
|
+
|
250
|
+
alias to_str to_s
|
251
|
+
|
252
|
+
# Returns whether or not the SID object is equal to +other+.
|
253
|
+
#
|
254
|
+
def ==(other)
|
255
|
+
EqualSid(@sid, other.sid)
|
256
|
+
end
|
257
|
+
|
258
|
+
# Returns whether or not the SID is a valid sid.
|
259
|
+
#
|
260
|
+
def valid?
|
261
|
+
IsValidSid(@sid)
|
262
|
+
end
|
263
|
+
|
264
|
+
# Returns whether or not the SID is a well known SID.
|
265
|
+
#
|
266
|
+
# Requires Windows XP or later. Earlier versions will raise a
|
267
|
+
# NoMethodError.
|
268
|
+
#
|
269
|
+
def well_known?
|
270
|
+
if defined? IsWellKnownSid
|
271
|
+
IsWellKnownSid(@sid)
|
272
|
+
else
|
273
|
+
raise NoMethodError, 'requires Windows XP or later'
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
# Returns the length of the SID object, in bytes.
|
278
|
+
#
|
279
|
+
def length
|
280
|
+
GetLengthSid(@sid)
|
281
|
+
end
|
282
|
+
|
283
|
+
private
|
284
|
+
|
285
|
+
# Converts a numeric account type into a human readable string.
|
286
|
+
#
|
287
|
+
def get_account_type(value)
|
288
|
+
case value
|
289
|
+
when SidTypeUser
|
290
|
+
'user'
|
291
|
+
when SidTypeGroup
|
292
|
+
'group'
|
293
|
+
when SidTypeDomain
|
294
|
+
'domain'
|
295
|
+
when SidTypeAlias
|
296
|
+
'alias'
|
297
|
+
when SidTypeWellKnownGroup
|
298
|
+
'well known group'
|
299
|
+
when SidTypeDeletedAccount
|
300
|
+
'deleted account'
|
301
|
+
when SidTypeInvalid
|
302
|
+
'invalid'
|
303
|
+
when SidTypeUnknown
|
304
|
+
'unknown'
|
305
|
+
when SidComputer
|
306
|
+
'computer'
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
data/test/test_acl.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
########################################################################
|
2
|
+
# test_acl.rb
|
3
|
+
#
|
4
|
+
# Test suite for the Win32::Security::ACL class. You should run these
|
5
|
+
# tests via the 'rake test' task.
|
6
|
+
########################################################################
|
7
|
+
require 'rubygems'
|
8
|
+
gem 'test-unit'
|
9
|
+
|
10
|
+
require 'win32/security'
|
11
|
+
require 'test/unit'
|
12
|
+
|
13
|
+
class TC_Win32_Security_Acl < Test::Unit::TestCase
|
14
|
+
def setup
|
15
|
+
@acl = Security::ACL.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_version
|
19
|
+
assert_equal('0.1.0', Security::ACL::VERSION)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_ace_count
|
23
|
+
assert_respond_to(@acl, :ace_count)
|
24
|
+
assert_kind_of(Fixnum, @acl.ace_count)
|
25
|
+
assert_equal(0, @acl.ace_count)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_acl
|
29
|
+
assert_respond_to(@acl, :acl)
|
30
|
+
assert_kind_of(String, @acl.acl)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_add_access_allowed_ace
|
34
|
+
assert_respond_to(@acl, :add_access_allowed_ace)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_add_access_denied_ace
|
38
|
+
assert_respond_to(@acl, :add_access_denied_ace)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_add_ace
|
42
|
+
assert_respond_to(@acl, :add_ace)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_delete_ace
|
46
|
+
assert_respond_to(@acl, :delete_ace)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_find_ace
|
50
|
+
assert_respond_to(@acl, :find_ace)
|
51
|
+
assert_kind_of(Fixnum, @acl.find_ace)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_revision
|
55
|
+
assert_respond_to(@acl, :revision)
|
56
|
+
assert_kind_of(Fixnum, @acl.revision)
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_is_valid
|
60
|
+
assert_respond_to(@acl, :valid?)
|
61
|
+
assert_equal(true, @acl.valid?)
|
62
|
+
end
|
63
|
+
|
64
|
+
def teardown
|
65
|
+
@acl = nil
|
66
|
+
end
|
67
|
+
end
|
data/test/test_security.rb
CHANGED
data/test/test_sid.rb
CHANGED
@@ -23,7 +23,7 @@ class TC_Win32_Security_Sid < Test::Unit::TestCase
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def test_version
|
26
|
-
assert_equal('0.1.
|
26
|
+
assert_equal('0.1.1', Security::SID::VERSION)
|
27
27
|
end
|
28
28
|
|
29
29
|
def test_sid
|
@@ -108,6 +108,16 @@ class TC_Win32_Security_Sid < Test::Unit::TestCase
|
|
108
108
|
assert_raise(Security::SID::Error){ Security::SID.new('bogus') }
|
109
109
|
end
|
110
110
|
|
111
|
+
def test_well_known_sid_constants
|
112
|
+
assert_equal('S-1-0', Security::SID::Null)
|
113
|
+
assert_equal('S-1-0-0', Security::SID::Nobody)
|
114
|
+
assert_equal('S-1-1', Security::SID::World)
|
115
|
+
assert_equal('S-1-1-0', Security::SID::Everyone)
|
116
|
+
assert_equal('S-1-5-32-544', Security::SID::BuiltinAdministrators)
|
117
|
+
assert_equal('S-1-5-32-545', Security::SID::BuiltinUsers)
|
118
|
+
assert_equal('S-1-5-32-546', Security::SID::Guests)
|
119
|
+
end
|
120
|
+
|
111
121
|
def teardown
|
112
122
|
@sid = nil
|
113
123
|
end
|
data/win32-security.gemspec
CHANGED
@@ -1,32 +1,31 @@
|
|
1
|
-
require
|
1
|
+
require 'rubygems'
|
2
2
|
|
3
3
|
spec = Gem::Specification.new do |gem|
|
4
|
-
gem.name
|
5
|
-
gem.version
|
6
|
-
gem.authors
|
7
|
-
gem.email
|
8
|
-
gem.homepage
|
9
|
-
gem.platform
|
10
|
-
gem.summary
|
11
|
-
gem.test_files
|
12
|
-
gem.has_rdoc
|
13
|
-
gem.files
|
14
|
-
gem.
|
15
|
-
|
16
|
-
gem.
|
17
|
-
|
18
|
-
gem.add_dependency("windows-pr", ">= 0.9.8")
|
19
|
-
gem.add_dependency("test-unit", ">= 2.0.1")
|
20
|
-
gem.add_dependency("sys-admin", ">= 1.4.4")
|
4
|
+
gem.name = 'win32-security'
|
5
|
+
gem.version = '0.1.1'
|
6
|
+
gem.authors = ['Daniel J. Berger', 'Park Heesob']
|
7
|
+
gem.email = 'djberg96@gmail.com'
|
8
|
+
gem.homepage = 'http://www.rubyforge.org/projects/win32utils'
|
9
|
+
gem.platform = Gem::Platform::RUBY
|
10
|
+
gem.summary = 'A library for dealing with aspects of Windows security.'
|
11
|
+
gem.test_files = Dir['test/*.rb']
|
12
|
+
gem.has_rdoc = true
|
13
|
+
gem.files = Dir['**/*'].reject{ |f| f.include?('CVS') }
|
14
|
+
gem.license = 'Artistic 2.0'
|
15
|
+
|
16
|
+
gem.extra_rdoc_files = ['README', 'CHANGES', 'MANIFEST']
|
17
|
+
gem.rubyforge_project = 'win32utils'
|
21
18
|
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
gem.add_dependency('windows-pr', '>= 0.9.8')
|
20
|
+
gem.add_dependency('test-unit', '>= 2.0.1')
|
21
|
+
gem.add_dependency('sys-admin', '>= 1.4.4')
|
25
22
|
|
26
|
-
gem.description =
|
23
|
+
gem.description = <<-EOF
|
24
|
+
The win32-security library provides an interface for dealing with
|
25
|
+
security related aspects of MS Windows. At the moment it provides an
|
26
|
+
interface for inspecting or creating SID's.
|
27
|
+
EOF
|
27
28
|
end
|
28
29
|
|
29
|
-
if
|
30
|
-
|
31
|
-
Gem::Builder.new(spec).build
|
32
|
-
end
|
30
|
+
Gem.manage_gems if Gem::RubyGemsVersion.to_f < 1.0
|
31
|
+
Gem::Builder.new(spec).build
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: win32-security
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel J. Berger
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date:
|
13
|
+
date: 2009-07-14 00:00:00 -06:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
- !ruby/object:Gem::Version
|
44
44
|
version: 1.4.4
|
45
45
|
version:
|
46
|
-
description: The win32-security library provides an interface for dealing with
|
46
|
+
description: " The win32-security library provides an interface for dealing with\n security related aspects of MS Windows. At the moment it provides an\n interface for inspecting or creating SID's.\n"
|
47
47
|
email: djberg96@gmail.com
|
48
48
|
executables: []
|
49
49
|
|
@@ -54,18 +54,20 @@ extra_rdoc_files:
|
|
54
54
|
- CHANGES
|
55
55
|
- MANIFEST
|
56
56
|
files:
|
57
|
-
- lib/win32/security.rb
|
58
|
-
- test/test_security.rb
|
59
|
-
- test/test_sid.rb
|
60
57
|
- CHANGES
|
61
|
-
- lib
|
58
|
+
- lib/win32/security/sid.rb
|
59
|
+
- lib/win32/security.rb
|
62
60
|
- MANIFEST
|
63
61
|
- Rakefile
|
64
62
|
- README
|
65
|
-
- test
|
63
|
+
- test/test_acl.rb
|
64
|
+
- test/test_security.rb
|
65
|
+
- test/test_sid.rb
|
66
66
|
- win32-security.gemspec
|
67
67
|
has_rdoc: true
|
68
68
|
homepage: http://www.rubyforge.org/projects/win32utils
|
69
|
+
licenses:
|
70
|
+
- Artistic 2.0
|
69
71
|
post_install_message:
|
70
72
|
rdoc_options: []
|
71
73
|
|
@@ -85,11 +87,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
87
|
version:
|
86
88
|
requirements: []
|
87
89
|
|
88
|
-
rubyforge_project:
|
89
|
-
rubygems_version: 1.3.
|
90
|
+
rubyforge_project: win32utils
|
91
|
+
rubygems_version: 1.3.4
|
90
92
|
signing_key:
|
91
|
-
specification_version:
|
93
|
+
specification_version: 3
|
92
94
|
summary: A library for dealing with aspects of Windows security.
|
93
95
|
test_files:
|
96
|
+
- test/test_acl.rb
|
94
97
|
- test/test_security.rb
|
95
98
|
- test/test_sid.rb
|