win32-security 0.1.3 → 0.1.4
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 +23 -19
- data/MANIFEST +8 -8
- data/README +35 -35
- data/Rakefile +46 -46
- data/lib/win32/security.rb +67 -67
- data/lib/win32/security/ace.rb +39 -39
- data/lib/win32/security/acl.rb +148 -148
- data/lib/win32/security/sid.rb +388 -381
- data/test/test_acl.rb +67 -67
- data/test/test_security.rb +34 -34
- data/test/test_sid.rb +141 -137
- data/win32-security.gemspec +27 -27
- metadata +2 -2
data/CHANGES
CHANGED
@@ -1,19 +1,23 @@
|
|
1
|
-
= 0.1.
|
2
|
-
*
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
*
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
*
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
*
|
1
|
+
= 0.1.4 - 4-Oct-2012
|
2
|
+
* Updated the SID.string_to_sid method so that it completes a string/sid
|
3
|
+
round trip successfully now. Thanks go to Josh Cooper for the patch.
|
4
|
+
|
5
|
+
= 0.1.3 - 12-Jul-2012
|
6
|
+
* The SID.new method now defaults to the owner of the current thread if
|
7
|
+
no account name is provided.
|
8
|
+
* Updates to the gemspec, Rakefile, and SID tests, including updates to
|
9
|
+
some of the gemspec dependencies.
|
10
|
+
|
11
|
+
= 0.1.2 - 2-Aug-2009
|
12
|
+
* Now compatible with Ruby 1.9.x.
|
13
|
+
* Switched test-unit and sys-admin from standard dependencies to development
|
14
|
+
dependencies.
|
15
|
+
|
16
|
+
= 0.1.1 - 14-Jul-2009
|
17
|
+
* Added some well known SID's as constants to the Win32::Security::SID class
|
18
|
+
for convenience, e.g. SID::World, SID::Everyone.
|
19
|
+
* Fixes for the gemspec.
|
20
|
+
* Changed license to Artistic 2.0.
|
21
|
+
|
22
|
+
= 0.1.0 - 17-Dec-2008
|
23
|
+
* Initial release
|
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
@@ -1,35 +1,35 @@
|
|
1
|
-
= Description
|
2
|
-
A security library for MS Windows that allows you to open existing or
|
3
|
-
create new security identifiers (SID's).
|
4
|
-
|
5
|
-
= Synopsis
|
6
|
-
require 'win32/security'
|
7
|
-
include Win32
|
8
|
-
|
9
|
-
sid = Security::SID.open('some_user')
|
10
|
-
|
11
|
-
sid.valid? # => true
|
12
|
-
sid.to_s # => "S-1-5-21-3733855671-1102023144-2002619019-1000"
|
13
|
-
sid.length # => 28
|
14
|
-
sid.sid # => "\001\005\000\000\000\000\000\005\025\000\000\000..."
|
15
|
-
|
16
|
-
== Future Plans
|
17
|
-
Create classes that encapsulate ACL's, ACE's, Token's, etc.
|
18
|
-
|
19
|
-
There are some unfinished versions of the ACL and ACE classes in the
|
20
|
-
repo if you're interested in taking a look.
|
21
|
-
|
22
|
-
== Known Issues
|
23
|
-
None that I'm aware of. Please file any bug reports on the project page
|
24
|
-
at http://www.rubyforge.org/projects/win32utils.
|
25
|
-
|
26
|
-
== License
|
27
|
-
Artistic 2.0
|
28
|
-
|
29
|
-
== Copyright
|
30
|
-
(C) 2003-2012 Daniel J. Berger
|
31
|
-
All Rights Reserved
|
32
|
-
|
33
|
-
== Authors
|
34
|
-
Daniel J. Berger
|
35
|
-
Park Heesob
|
1
|
+
= Description
|
2
|
+
A security library for MS Windows that allows you to open existing or
|
3
|
+
create new security identifiers (SID's).
|
4
|
+
|
5
|
+
= Synopsis
|
6
|
+
require 'win32/security'
|
7
|
+
include Win32
|
8
|
+
|
9
|
+
sid = Security::SID.open('some_user')
|
10
|
+
|
11
|
+
sid.valid? # => true
|
12
|
+
sid.to_s # => "S-1-5-21-3733855671-1102023144-2002619019-1000"
|
13
|
+
sid.length # => 28
|
14
|
+
sid.sid # => "\001\005\000\000\000\000\000\005\025\000\000\000..."
|
15
|
+
|
16
|
+
== Future Plans
|
17
|
+
Create classes that encapsulate ACL's, ACE's, Token's, etc.
|
18
|
+
|
19
|
+
There are some unfinished versions of the ACL and ACE classes in the
|
20
|
+
repo if you're interested in taking a look.
|
21
|
+
|
22
|
+
== Known Issues
|
23
|
+
None that I'm aware of. Please file any bug reports on the project page
|
24
|
+
at http://www.rubyforge.org/projects/win32utils.
|
25
|
+
|
26
|
+
== License
|
27
|
+
Artistic 2.0
|
28
|
+
|
29
|
+
== Copyright
|
30
|
+
(C) 2003-2012 Daniel J. Berger
|
31
|
+
All Rights Reserved
|
32
|
+
|
33
|
+
== Authors
|
34
|
+
Daniel J. Berger
|
35
|
+
Park Heesob
|
data/Rakefile
CHANGED
@@ -1,46 +1,46 @@
|
|
1
|
-
require 'rake'
|
2
|
-
require 'rake/testtask'
|
3
|
-
require 'rbconfig'
|
4
|
-
|
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
|
10
|
-
|
11
|
-
desc "Create the win32-security gem"
|
12
|
-
task :create => [:clean] do
|
13
|
-
spec = eval(IO.read('win32-security.gemspec'))
|
14
|
-
Gem::Builder.new(spec).build
|
15
|
-
end
|
16
|
-
|
17
|
-
desc "Install the win32-security gem"
|
18
|
-
task :install => [:create] do
|
19
|
-
ruby 'win32-security.gemspec'
|
20
|
-
file = Dir["*.gem"].first
|
21
|
-
sh "gem install #{file}"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
namespace :test do
|
26
|
-
Rake::TestTask.new(:security) do |t|
|
27
|
-
t.verbose = true
|
28
|
-
t.warning = true
|
29
|
-
t.test_files = Dir['test/test_security.rb']
|
30
|
-
end
|
31
|
-
|
32
|
-
Rake::TestTask.new(:sid) do |t|
|
33
|
-
t.verbose = true
|
34
|
-
t.warning = true
|
35
|
-
t.test_files = Dir['test/test_sid.rb']
|
36
|
-
end
|
37
|
-
|
38
|
-
# ACL class isn't ready yet
|
39
|
-
Rake::TestTask.new(:all) do |t|
|
40
|
-
t.verbose = true
|
41
|
-
t.warning = true
|
42
|
-
t.test_files = Dir['test/test_sid.rb', 'test/test_security.rb']
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
task :default => 'test:all'
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rbconfig'
|
4
|
+
|
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
|
10
|
+
|
11
|
+
desc "Create the win32-security gem"
|
12
|
+
task :create => [:clean] do
|
13
|
+
spec = eval(IO.read('win32-security.gemspec'))
|
14
|
+
Gem::Builder.new(spec).build
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Install the win32-security gem"
|
18
|
+
task :install => [:create] do
|
19
|
+
ruby 'win32-security.gemspec'
|
20
|
+
file = Dir["*.gem"].first
|
21
|
+
sh "gem install #{file}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
namespace :test do
|
26
|
+
Rake::TestTask.new(:security) do |t|
|
27
|
+
t.verbose = true
|
28
|
+
t.warning = true
|
29
|
+
t.test_files = Dir['test/test_security.rb']
|
30
|
+
end
|
31
|
+
|
32
|
+
Rake::TestTask.new(:sid) do |t|
|
33
|
+
t.verbose = true
|
34
|
+
t.warning = true
|
35
|
+
t.test_files = Dir['test/test_sid.rb']
|
36
|
+
end
|
37
|
+
|
38
|
+
# ACL class isn't ready yet
|
39
|
+
Rake::TestTask.new(:all) do |t|
|
40
|
+
t.verbose = true
|
41
|
+
t.warning = true
|
42
|
+
t.test_files = Dir['test/test_sid.rb', 'test/test_security.rb']
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
task :default => 'test:all'
|
data/lib/win32/security.rb
CHANGED
@@ -1,67 +1,67 @@
|
|
1
|
-
# This file allows users to require all security related classes from
|
2
|
-
# a single file, instead of having to require individual files.
|
3
|
-
|
4
|
-
require 'windows/process'
|
5
|
-
require 'windows/security'
|
6
|
-
require 'windows/handle'
|
7
|
-
require 'windows/error'
|
8
|
-
|
9
|
-
# The Win32 module serves as a namespace only.
|
10
|
-
module Win32
|
11
|
-
|
12
|
-
# The Security class encapsulates security aspects of MS Windows.
|
13
|
-
class Security
|
14
|
-
|
15
|
-
# Base error class for all Win32::Security errors.
|
16
|
-
class Error < StandardError; end
|
17
|
-
|
18
|
-
include Windows::Security
|
19
|
-
|
20
|
-
extend Windows::Process
|
21
|
-
extend Windows::Security
|
22
|
-
extend Windows::Handle
|
23
|
-
extend Windows::Error
|
24
|
-
|
25
|
-
# The version of the win32-security library
|
26
|
-
VERSION = '0.1.
|
27
|
-
|
28
|
-
# Returns whether or not the owner of the current process is running
|
29
|
-
# with elevated security privileges.
|
30
|
-
#
|
31
|
-
# Only supported on Windows Vista or later.
|
32
|
-
#
|
33
|
-
def self.elevated_security?
|
34
|
-
token = 0.chr * 4
|
35
|
-
|
36
|
-
unless OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, token)
|
37
|
-
raise Error, get_last_error
|
38
|
-
end
|
39
|
-
|
40
|
-
begin
|
41
|
-
token = token.unpack('V')[0]
|
42
|
-
|
43
|
-
te = 0.chr * 4 # TOKEN_ELEVATION
|
44
|
-
rl = 0.chr * 4 # Return length
|
45
|
-
|
46
|
-
bool = GetTokenInformation(
|
47
|
-
token,
|
48
|
-
TokenElevation,
|
49
|
-
te,
|
50
|
-
te.size,
|
51
|
-
rl
|
52
|
-
)
|
53
|
-
|
54
|
-
raise Error, get_last_error unless bool
|
55
|
-
ensure
|
56
|
-
CloseHandle(token)
|
57
|
-
end
|
58
|
-
|
59
|
-
# TokenIsElevated member of the TOKEN_ELEVATION struct
|
60
|
-
te.unpack('L')[0] != 0
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
require 'win32/security/sid'
|
66
|
-
#require 'win32/security/acl'
|
67
|
-
#require 'win32/security/ace'
|
1
|
+
# This file allows users to require all security related classes from
|
2
|
+
# a single file, instead of having to require individual files.
|
3
|
+
|
4
|
+
require 'windows/process'
|
5
|
+
require 'windows/security'
|
6
|
+
require 'windows/handle'
|
7
|
+
require 'windows/error'
|
8
|
+
|
9
|
+
# The Win32 module serves as a namespace only.
|
10
|
+
module Win32
|
11
|
+
|
12
|
+
# The Security class encapsulates security aspects of MS Windows.
|
13
|
+
class Security
|
14
|
+
|
15
|
+
# Base error class for all Win32::Security errors.
|
16
|
+
class Error < StandardError; end
|
17
|
+
|
18
|
+
include Windows::Security
|
19
|
+
|
20
|
+
extend Windows::Process
|
21
|
+
extend Windows::Security
|
22
|
+
extend Windows::Handle
|
23
|
+
extend Windows::Error
|
24
|
+
|
25
|
+
# The version of the win32-security library
|
26
|
+
VERSION = '0.1.4'
|
27
|
+
|
28
|
+
# Returns whether or not the owner of the current process is running
|
29
|
+
# with elevated security privileges.
|
30
|
+
#
|
31
|
+
# Only supported on Windows Vista or later.
|
32
|
+
#
|
33
|
+
def self.elevated_security?
|
34
|
+
token = 0.chr * 4
|
35
|
+
|
36
|
+
unless OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, token)
|
37
|
+
raise Error, get_last_error
|
38
|
+
end
|
39
|
+
|
40
|
+
begin
|
41
|
+
token = token.unpack('V')[0]
|
42
|
+
|
43
|
+
te = 0.chr * 4 # TOKEN_ELEVATION
|
44
|
+
rl = 0.chr * 4 # Return length
|
45
|
+
|
46
|
+
bool = GetTokenInformation(
|
47
|
+
token,
|
48
|
+
TokenElevation,
|
49
|
+
te,
|
50
|
+
te.size,
|
51
|
+
rl
|
52
|
+
)
|
53
|
+
|
54
|
+
raise Error, get_last_error unless bool
|
55
|
+
ensure
|
56
|
+
CloseHandle(token)
|
57
|
+
end
|
58
|
+
|
59
|
+
# TokenIsElevated member of the TOKEN_ELEVATION struct
|
60
|
+
te.unpack('L')[0] != 0
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
require 'win32/security/sid'
|
66
|
+
#require 'win32/security/acl'
|
67
|
+
#require 'win32/security/ace'
|
data/lib/win32/security/ace.rb
CHANGED
@@ -1,39 +1,39 @@
|
|
1
|
-
# The Win32 module serves as a namespace only.
|
2
|
-
module Win32
|
3
|
-
|
4
|
-
# The Security class serves as a toplevel class namespace.
|
5
|
-
class Security
|
6
|
-
|
7
|
-
# The ACE class encapsulates an Access Control Entry, an element within
|
8
|
-
# an Access Control List.
|
9
|
-
class ACE
|
10
|
-
# The version of the Win32::Security::ACE class.
|
11
|
-
VERSION = '0.1.0'
|
12
|
-
|
13
|
-
# The ACE type, e.g. ACCESS_ALLOWED, ACCESS_DENIED, etc.
|
14
|
-
attr_accessor :ace_type
|
15
|
-
|
16
|
-
# The ACE mask, e.g. INHERITED_ACE
|
17
|
-
attr_accessor :ace_mask
|
18
|
-
|
19
|
-
# Standard access rights, e.g. GENERIC_READ, GENERIC_WRITE, etc
|
20
|
-
attr_accessor :access_mask
|
21
|
-
|
22
|
-
# Bit flags that indicate whether the ObjectType and
|
23
|
-
# InheritedObjectType members are present. This value is set
|
24
|
-
# internally based on the values passed to the ACE#object_type or
|
25
|
-
# ACE#inherited_object_type methods, if any.
|
26
|
-
attr_reader :flags
|
27
|
-
|
28
|
-
# A Win32::Security::GUID object that identifies the type of child
|
29
|
-
# object that can inherit the ACE.
|
30
|
-
attr_accessor :object_type
|
31
|
-
|
32
|
-
attr_accessor :inherited_object_type
|
33
|
-
|
34
|
-
def initialize
|
35
|
-
yield self if block_given?
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
1
|
+
# The Win32 module serves as a namespace only.
|
2
|
+
module Win32
|
3
|
+
|
4
|
+
# The Security class serves as a toplevel class namespace.
|
5
|
+
class Security
|
6
|
+
|
7
|
+
# The ACE class encapsulates an Access Control Entry, an element within
|
8
|
+
# an Access Control List.
|
9
|
+
class ACE
|
10
|
+
# The version of the Win32::Security::ACE class.
|
11
|
+
VERSION = '0.1.0'
|
12
|
+
|
13
|
+
# The ACE type, e.g. ACCESS_ALLOWED, ACCESS_DENIED, etc.
|
14
|
+
attr_accessor :ace_type
|
15
|
+
|
16
|
+
# The ACE mask, e.g. INHERITED_ACE
|
17
|
+
attr_accessor :ace_mask
|
18
|
+
|
19
|
+
# Standard access rights, e.g. GENERIC_READ, GENERIC_WRITE, etc
|
20
|
+
attr_accessor :access_mask
|
21
|
+
|
22
|
+
# Bit flags that indicate whether the ObjectType and
|
23
|
+
# InheritedObjectType members are present. This value is set
|
24
|
+
# internally based on the values passed to the ACE#object_type or
|
25
|
+
# ACE#inherited_object_type methods, if any.
|
26
|
+
attr_reader :flags
|
27
|
+
|
28
|
+
# A Win32::Security::GUID object that identifies the type of child
|
29
|
+
# object that can inherit the ACE.
|
30
|
+
attr_accessor :object_type
|
31
|
+
|
32
|
+
attr_accessor :inherited_object_type
|
33
|
+
|
34
|
+
def initialize
|
35
|
+
yield self if block_given?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/win32/security/acl.rb
CHANGED
@@ -1,148 +1,148 @@
|
|
1
|
-
require 'windows/security'
|
2
|
-
require 'windows/error'
|
3
|
-
require 'windows/limits'
|
4
|
-
require 'windows/msvcrt/buffer'
|
5
|
-
|
6
|
-
# The Win32 module serves as a namespace only.
|
7
|
-
module Win32
|
8
|
-
|
9
|
-
# The Security class serves as a toplevel class namespace.
|
10
|
-
class Security
|
11
|
-
|
12
|
-
# The ACL class encapsulates an Access Control List.
|
13
|
-
class ACL
|
14
|
-
include Windows::Error
|
15
|
-
include Windows::Security
|
16
|
-
include Windows::Limits
|
17
|
-
include Windows::MSVCRT::Buffer
|
18
|
-
|
19
|
-
# The version of the Win32::Security::ACL class.
|
20
|
-
VERSION = '0.1.0'
|
21
|
-
|
22
|
-
# The binary representation of the ACL structure
|
23
|
-
attr_reader :acl
|
24
|
-
|
25
|
-
# The revision level.
|
26
|
-
attr_reader :revision
|
27
|
-
|
28
|
-
# Creates and returns a new Win32::Security::ACL object. This object
|
29
|
-
# encapsulates an ACL structure, including a binary representation of
|
30
|
-
# the ACL itself, and the revision information.
|
31
|
-
#
|
32
|
-
def initialize(revision = ACL_REVISION)
|
33
|
-
acl = 0.chr * 8 # This can be increased later as needed
|
34
|
-
|
35
|
-
unless InitializeAcl(acl, acl.size, revision)
|
36
|
-
raise Error, get_last_error
|
37
|
-
end
|
38
|
-
|
39
|
-
@acl = acl
|
40
|
-
@revision = revision
|
41
|
-
end
|
42
|
-
|
43
|
-
# Returns the number of ACE's in the ACL object.
|
44
|
-
#
|
45
|
-
def ace_count
|
46
|
-
buf = 0.chr * 12 # sizeof(ACL_SIZE_INFORMATION)
|
47
|
-
|
48
|
-
unless GetAclInformation(@acl, buf, buf.size, AclSizeInformation)
|
49
|
-
raise Error, get_last_error
|
50
|
-
end
|
51
|
-
|
52
|
-
buf[0, 4].unpack('L')[0]
|
53
|
-
end
|
54
|
-
|
55
|
-
# Adds an access allowed ACE to the given +sid+. The +mask+ is a
|
56
|
-
# bitwise OR'd value of access rights.
|
57
|
-
#
|
58
|
-
def add_access_allowed_ace(sid, mask=0)
|
59
|
-
unless AddAccessAllowedAce(@acl, @revision, mask, sid)
|
60
|
-
raise Error, get_last_error
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
# Adds an access denied ACE to the given +sid+.
|
65
|
-
#
|
66
|
-
def add_access_denied_ace(sid, mask=0)
|
67
|
-
unless AddAccessDeniedAce(@acl, @revision, mask, sid)
|
68
|
-
raise Error, get_last_error
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# Adds an ACE to the ACL object with the given +revision+ at +index+
|
73
|
-
# or the end of the chain if no index is specified.
|
74
|
-
#
|
75
|
-
# Returns the index if successful.
|
76
|
-
#--
|
77
|
-
# This is untested and will require an actual implementation of
|
78
|
-
# Win32::Security::Ace before it can work properly.
|
79
|
-
#
|
80
|
-
def add_ace(ace, index=MAXDWORD)
|
81
|
-
unless AddAce(@acl, @revision, index, ace, ace.length)
|
82
|
-
raise Error, get_last_error
|
83
|
-
end
|
84
|
-
|
85
|
-
index
|
86
|
-
end
|
87
|
-
|
88
|
-
# Deletes an ACE from the ACL object at +index+, or from the end of
|
89
|
-
# the chain if no index is specified.
|
90
|
-
#
|
91
|
-
# Returns the index if successful.
|
92
|
-
#--
|
93
|
-
# This is untested and will require an actual implementation of
|
94
|
-
# Win32::Security::Ace before it can work properly.
|
95
|
-
#
|
96
|
-
def delete_ace(index=MAXDWORD)
|
97
|
-
unless DeleteAce(@ace, index)
|
98
|
-
raise Error, get_last_error
|
99
|
-
end
|
100
|
-
|
101
|
-
index
|
102
|
-
end
|
103
|
-
|
104
|
-
# Finds and returns a pointer (address) to an ACE in the ACL at the
|
105
|
-
# given +index+. If no index is provided, then an address to the
|
106
|
-
# first free byte of the ACL is returned.
|
107
|
-
#
|
108
|
-
def find_ace(index = nil)
|
109
|
-
ptr = [0].pack('L')
|
110
|
-
|
111
|
-
if index.nil?
|
112
|
-
unless FindFirstFreeAce(@acl, ptr)
|
113
|
-
raise Error, get_last_error
|
114
|
-
end
|
115
|
-
else
|
116
|
-
unless GetAce(@acl, index, ptr)
|
117
|
-
raise Error, get_last_error
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
[ptr].pack('p*').unpack('L')[0]
|
122
|
-
end
|
123
|
-
|
124
|
-
# Sets the revision information level, where the +revision_level+
|
125
|
-
# can be ACL_REVISION1, ACL_REVISION2, ACL_REVISION3 or ACL_REVISION4.
|
126
|
-
#
|
127
|
-
# Returns the revision level if successful.
|
128
|
-
#
|
129
|
-
def revision=(revision_level)
|
130
|
-
buf = [revision_level].pack('L')
|
131
|
-
|
132
|
-
unless SetAclInformation(@acl, buf, buf.size, AclRevisionInformation)
|
133
|
-
raise Error, get_last_error
|
134
|
-
end
|
135
|
-
|
136
|
-
@revision = revision_level
|
137
|
-
|
138
|
-
revision_level
|
139
|
-
end
|
140
|
-
|
141
|
-
# Returns whether or not the ACL is a valid ACL.
|
142
|
-
#
|
143
|
-
def valid?
|
144
|
-
IsValidAcl(@acl)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
1
|
+
require 'windows/security'
|
2
|
+
require 'windows/error'
|
3
|
+
require 'windows/limits'
|
4
|
+
require 'windows/msvcrt/buffer'
|
5
|
+
|
6
|
+
# The Win32 module serves as a namespace only.
|
7
|
+
module Win32
|
8
|
+
|
9
|
+
# The Security class serves as a toplevel class namespace.
|
10
|
+
class Security
|
11
|
+
|
12
|
+
# The ACL class encapsulates an Access Control List.
|
13
|
+
class ACL
|
14
|
+
include Windows::Error
|
15
|
+
include Windows::Security
|
16
|
+
include Windows::Limits
|
17
|
+
include Windows::MSVCRT::Buffer
|
18
|
+
|
19
|
+
# The version of the Win32::Security::ACL class.
|
20
|
+
VERSION = '0.1.0'
|
21
|
+
|
22
|
+
# The binary representation of the ACL structure
|
23
|
+
attr_reader :acl
|
24
|
+
|
25
|
+
# The revision level.
|
26
|
+
attr_reader :revision
|
27
|
+
|
28
|
+
# Creates and returns a new Win32::Security::ACL object. This object
|
29
|
+
# encapsulates an ACL structure, including a binary representation of
|
30
|
+
# the ACL itself, and the revision information.
|
31
|
+
#
|
32
|
+
def initialize(revision = ACL_REVISION)
|
33
|
+
acl = 0.chr * 8 # This can be increased later as needed
|
34
|
+
|
35
|
+
unless InitializeAcl(acl, acl.size, revision)
|
36
|
+
raise Error, get_last_error
|
37
|
+
end
|
38
|
+
|
39
|
+
@acl = acl
|
40
|
+
@revision = revision
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the number of ACE's in the ACL object.
|
44
|
+
#
|
45
|
+
def ace_count
|
46
|
+
buf = 0.chr * 12 # sizeof(ACL_SIZE_INFORMATION)
|
47
|
+
|
48
|
+
unless GetAclInformation(@acl, buf, buf.size, AclSizeInformation)
|
49
|
+
raise Error, get_last_error
|
50
|
+
end
|
51
|
+
|
52
|
+
buf[0, 4].unpack('L')[0]
|
53
|
+
end
|
54
|
+
|
55
|
+
# Adds an access allowed ACE to the given +sid+. The +mask+ is a
|
56
|
+
# bitwise OR'd value of access rights.
|
57
|
+
#
|
58
|
+
def add_access_allowed_ace(sid, mask=0)
|
59
|
+
unless AddAccessAllowedAce(@acl, @revision, mask, sid)
|
60
|
+
raise Error, get_last_error
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Adds an access denied ACE to the given +sid+.
|
65
|
+
#
|
66
|
+
def add_access_denied_ace(sid, mask=0)
|
67
|
+
unless AddAccessDeniedAce(@acl, @revision, mask, sid)
|
68
|
+
raise Error, get_last_error
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Adds an ACE to the ACL object with the given +revision+ at +index+
|
73
|
+
# or the end of the chain if no index is specified.
|
74
|
+
#
|
75
|
+
# Returns the index if successful.
|
76
|
+
#--
|
77
|
+
# This is untested and will require an actual implementation of
|
78
|
+
# Win32::Security::Ace before it can work properly.
|
79
|
+
#
|
80
|
+
def add_ace(ace, index=MAXDWORD)
|
81
|
+
unless AddAce(@acl, @revision, index, ace, ace.length)
|
82
|
+
raise Error, get_last_error
|
83
|
+
end
|
84
|
+
|
85
|
+
index
|
86
|
+
end
|
87
|
+
|
88
|
+
# Deletes an ACE from the ACL object at +index+, or from the end of
|
89
|
+
# the chain if no index is specified.
|
90
|
+
#
|
91
|
+
# Returns the index if successful.
|
92
|
+
#--
|
93
|
+
# This is untested and will require an actual implementation of
|
94
|
+
# Win32::Security::Ace before it can work properly.
|
95
|
+
#
|
96
|
+
def delete_ace(index=MAXDWORD)
|
97
|
+
unless DeleteAce(@ace, index)
|
98
|
+
raise Error, get_last_error
|
99
|
+
end
|
100
|
+
|
101
|
+
index
|
102
|
+
end
|
103
|
+
|
104
|
+
# Finds and returns a pointer (address) to an ACE in the ACL at the
|
105
|
+
# given +index+. If no index is provided, then an address to the
|
106
|
+
# first free byte of the ACL is returned.
|
107
|
+
#
|
108
|
+
def find_ace(index = nil)
|
109
|
+
ptr = [0].pack('L')
|
110
|
+
|
111
|
+
if index.nil?
|
112
|
+
unless FindFirstFreeAce(@acl, ptr)
|
113
|
+
raise Error, get_last_error
|
114
|
+
end
|
115
|
+
else
|
116
|
+
unless GetAce(@acl, index, ptr)
|
117
|
+
raise Error, get_last_error
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
[ptr].pack('p*').unpack('L')[0]
|
122
|
+
end
|
123
|
+
|
124
|
+
# Sets the revision information level, where the +revision_level+
|
125
|
+
# can be ACL_REVISION1, ACL_REVISION2, ACL_REVISION3 or ACL_REVISION4.
|
126
|
+
#
|
127
|
+
# Returns the revision level if successful.
|
128
|
+
#
|
129
|
+
def revision=(revision_level)
|
130
|
+
buf = [revision_level].pack('L')
|
131
|
+
|
132
|
+
unless SetAclInformation(@acl, buf, buf.size, AclRevisionInformation)
|
133
|
+
raise Error, get_last_error
|
134
|
+
end
|
135
|
+
|
136
|
+
@revision = revision_level
|
137
|
+
|
138
|
+
revision_level
|
139
|
+
end
|
140
|
+
|
141
|
+
# Returns whether or not the ACL is a valid ACL.
|
142
|
+
#
|
143
|
+
def valid?
|
144
|
+
IsValidAcl(@acl)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|