win32-security 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -25,7 +25,7 @@ module Win32
25
25
  extend Windows::Error
26
26
 
27
27
  # The version of the win32-security library
28
- VERSION = '0.1.0'
28
+ VERSION = '0.1.1'
29
29
 
30
30
  # Returns whether or not the owner of the current process is running
31
31
  # with elevated security privileges.
@@ -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
@@ -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
@@ -12,7 +12,7 @@ require 'win32/security'
12
12
 
13
13
  class TC_Win32_Security < Test::Unit::TestCase
14
14
  def test_version
15
- assert_equal('0.1.0', Win32::Security::VERSION)
15
+ assert_equal('0.1.1', Win32::Security::VERSION)
16
16
  end
17
17
 
18
18
  def test_elevated_security
@@ -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.0', Security::SID::VERSION)
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
@@ -1,32 +1,31 @@
1
- require "rubygems"
1
+ require 'rubygems'
2
2
 
3
3
  spec = Gem::Specification.new do |gem|
4
- gem.name = "win32-security"
5
- gem.version = "0.1.0"
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["lib/win32/*.rb"] + Dir["test/*"] + Dir["[A-Z]*"]
14
- gem.files.reject! { |fn| fn.include? "CVS" }
15
- gem.extra_rdoc_files = ["README", "CHANGES", "MANIFEST"]
16
- gem.rubyforge_project = 'Win32Utils'
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
- description = "The win32-security library provides an interface for dealing"
23
- description << " with security aspects of MS Windows. It includes classes"
24
- description << " for SID's, ACL's and ACE's."
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 = 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 $0 == __FILE__
30
- Gem.manage_gems if Gem::RubyGemsVersion.to_f < 1.0
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.0
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: 2008-12-17 00:00:00 -07:00
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 security aspects of MS Windows. It includes classes for SID's, ACL's and ACE's.
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: Win32Utils
89
- rubygems_version: 1.3.1
90
+ rubyforge_project: win32utils
91
+ rubygems_version: 1.3.4
90
92
  signing_key:
91
- specification_version: 2
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