win32-security 0.2.5 → 0.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 55e26f7dee9565c7f2bbcb65430d048ee8fde06e
4
- data.tar.gz: f56540e1e2536ad249d493f772b12ff132797cec
3
+ metadata.gz: a1ab1418254e685f2d1fb9ab37e728f190d55084
4
+ data.tar.gz: c4264cb93ef3630c6234682b47f311e7853368cb
5
5
  SHA512:
6
- metadata.gz: 7c2956d92cbcce0951f7b67150bdd324754e42c8faac2d5e2068e25d2bada7d12588c44775bb1c6d427415f0965f8792473a7c98c0ff57925b1f2861e0b2b605
7
- data.tar.gz: e9676d488e07a8648b5e19227e5a396bb815b1377740044ac68e479bfc2489019a5fcf818ece2f63f70a4afd03788b820973c4d292d65975f83c8ff9a03ab193
6
+ metadata.gz: e24cc326c44285834c0c743415e4a5b3510600a5af79a5556bdc859d88e46110e4e1cd78826883e993aa343005c86ef0c1c9ac385a82d722e9290816f0a80e70
7
+ data.tar.gz: a39286489abc37813946ccedb911f19d02cceb149923f938a4b522042742241b476695cf89cbdcfd020d910b14951852e4433468e487ebbe16ff19c58d3ffaf0
data/CHANGES CHANGED
@@ -1,3 +1,10 @@
1
+ == 0.3.0 - 31-Oct-2014
2
+ * Implemented an ACL class that lets you create and inspect acccess
3
+ control lists.
4
+ * Implemented a basic ACE class that encapsulates an ACE object.
5
+ * Removed Windows XP support.
6
+ * Some minor updates to the Rakefile and gemspec.
7
+
1
8
  == 0.2.5 - 24-Feb-2014
2
9
  * Fixed a bug in the SID#string_to_sid method. Thanks go to Rob Reynolds
3
10
  for the spot.
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,6 +1,7 @@
1
1
  = Description
2
2
  A security library for MS Windows that allows you to open existing or
3
- create new security identifiers (SID's).
3
+ create new security identifiers (SID's), as well as create access
4
+ control lists (ACL's).
4
5
 
5
6
  = Synopsis
6
7
  require 'win32/security'
@@ -12,15 +13,28 @@
12
13
  sid.to_s # => "S-1-5-21-3733855671-1102023144-2002619019-1000"
13
14
  sid.length # => 28
14
15
  sid.sid # => "\001\005\000\000\000\000\000\005\025\000\000\000..."
16
+
17
+ acl = Security::ACL.new
18
+ mask = Security::ACL::GENERIC_READ | Security::ACL::GENERIC_WRITE
19
+
20
+ acl.add_access_allowed_ace('some_user', mask)
21
+ acl.add_access_denied_ace('some_user', Security::ACL::GENERIC_EXECUTE)
22
+
23
+ acl.acl_count # => 2
24
+ acl.valid? # => true
15
25
 
16
26
  == Future Plans
17
- Create classes that encapsulate ACL's, ACE's, Token's, etc.
27
+ Create classes that encapsulate ACE's and Tokens.
18
28
 
19
- There are some unfinished versions of the ACL and ACE classes in the
20
- repo if you're interested in taking a look.
29
+ There is an unfinished versions of the ACE class in the repo if you're
30
+ interested in taking a look.
21
31
 
22
32
  == Known Issues
23
- None that I'm aware of. Please file any bug reports on the project page at:
33
+ There appears to be an issue with 64-bit versions of JRuby. I believe this
34
+ is related to this issue: https://github.com/jruby/jruby/issues/1315. There
35
+ is nothing I can do about it here.
36
+
37
+ Please file any other bug reports on the project page at:
24
38
 
25
39
  https://github.com/djberg96/win32-security
26
40
 
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ namespace :gem do
9
9
  desc "Create the win32-security gem"
10
10
  task :create => [:clean] do
11
11
  spec = eval(IO.read('win32-security.gemspec'))
12
- if Gem::VERSION < "2.0.0"
12
+ if Gem::VERSION < "2.0"
13
13
  Gem::Builder.new(spec).build
14
14
  else
15
15
  require 'rubygems/package'
@@ -21,7 +21,7 @@ namespace :gem do
21
21
  task :install => [:create] do
22
22
  ruby 'win32-security.gemspec'
23
23
  file = Dir["*.gem"].first
24
- sh "gem install #{file}"
24
+ sh "gem install -l #{file}"
25
25
  end
26
26
  end
27
27
 
@@ -38,6 +38,12 @@ namespace :test do
38
38
  t.test_files = Dir['test/test_acl.rb']
39
39
  end
40
40
 
41
+ Rake::TestTask.new(:ace) do |t|
42
+ t.verbose = true
43
+ t.warning = true
44
+ t.test_files = Dir['test/test_ace.rb']
45
+ end
46
+
41
47
  Rake::TestTask.new(:sid) do |t|
42
48
  t.verbose = true
43
49
  t.warning = true
@@ -1,9 +1,9 @@
1
1
  # This file allows users to require all security related classes from
2
2
  # a single file, instead of having to require individual files.
3
3
 
4
- require File.join(File.dirname(__FILE__), 'security', 'windows', 'constants')
5
- require File.join(File.dirname(__FILE__), 'security', 'windows', 'structs')
6
- require File.join(File.dirname(__FILE__), 'security', 'windows', 'functions')
4
+ require_relative 'security/windows/constants'
5
+ require_relative 'security/windows/structs'
6
+ require_relative 'security/windows/functions'
7
7
 
8
8
  # The Win32 module serves as a namespace only.
9
9
  module Win32
@@ -20,7 +20,7 @@ module Win32
20
20
  extend Windows::Security::Functions
21
21
 
22
22
  # The version of the win32-security library
23
- VERSION = '0.2.5'
23
+ VERSION = '0.3.0'
24
24
 
25
25
  # Used by OpenProcessToken
26
26
  TOKEN_QUERY = 8
@@ -33,35 +33,9 @@ module Win32
33
33
  # group.
34
34
  #
35
35
  def self.elevated_security?
36
- if windows_version < 6
37
- sid_ptr = FFI::MemoryPointer.new(:pointer)
38
- nt_auth_ptr = FFI::MemoryPointer.new(SID_IDENTIFIER_AUTHORITY,1)
39
-
40
- nt_auth = SID_IDENTIFIER_AUTHORITY.new(nt_auth_ptr)
41
- nt_auth[:Value].to_ptr.put_bytes(0, 0.chr*5 + 5.chr)
42
-
43
- bool = AllocateAndInitializeSid(
44
- nt_auth_ptr,
45
- 2,
46
- SECURITY_BUILTIN_DOMAIN_RID,
47
- DOMAIN_ALIAS_RID_ADMINS,
48
- 0, 0, 0, 0, 0, 0,
49
- sid_ptr
50
- )
51
- unless bool
52
- raise SystemCallError.new("AllocateAndInitializeSid", FFI.errno)
53
- end
54
-
55
- pbool = FFI::MemoryPointer.new(:long)
56
-
57
- unless CheckTokenMembership(0, sid_ptr.read_pointer, pbool)
58
- raise SystemCallError.new("CheckTokenMembership", FFI.errno)
59
- end
60
-
61
- pbool.read_long != 0
62
- else
63
- token = FFI::MemoryPointer.new(:uintptr_t)
36
+ result = false
64
37
 
38
+ FFI::MemoryPointer.new(:uintptr_t) do |token|
65
39
  unless OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, token)
66
40
  raise SystemCallError.new("OpenProcessToken", FFI.errno)
67
41
  end
@@ -82,12 +56,16 @@ module Win32
82
56
  )
83
57
 
84
58
  raise SystemCallError.new("GetTokenInformation", FFI.errno) unless bool
59
+
60
+ result = te.read_ulong != 0
85
61
  ensure
86
62
  CloseHandle(token)
63
+ te.free
64
+ rl.free
87
65
  end
88
-
89
- te.read_ulong != 0
90
66
  end
67
+
68
+ result
91
69
  end
92
70
 
93
71
  private
@@ -107,4 +85,4 @@ end
107
85
 
108
86
  require 'win32/security/sid'
109
87
  require 'win32/security/acl'
110
- #require 'win32/security/ace'
88
+ require 'win32/security/ace'
@@ -1,39 +1,75 @@
1
1
  # The Win32 module serves as a namespace only.
2
2
  module Win32
3
-
3
+
4
4
  # The Security class serves as a toplevel class namespace.
5
5
  class Security
6
-
6
+
7
7
  # The ACE class encapsulates an Access Control Entry, an element within
8
8
  # an Access Control List.
9
9
  class ACE
10
10
  # The version of the Win32::Security::ACE class.
11
11
  VERSION = '0.1.0'
12
12
 
13
- # The ACE type, e.g. ACCESS_ALLOWED, ACCESS_DENIED, etc.
13
+ # The ACE type, e.g. ACCESS_ALLOWED, ACCESS_DENIED, etc. This is an integer.
14
14
  attr_accessor :ace_type
15
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
16
+ # Standard access rights, e.g. GENERIC_READ, GENERIC_WRITE, etc.
17
+ # This is an integer.
20
18
  attr_accessor :access_mask
21
19
 
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.
20
+ # Bit flags associated with the ACE, e.g. OBJECT_INHERIT_ACE, etc.
21
+ # This is an integer.
26
22
  attr_reader :flags
27
23
 
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
24
+ # Creates and returns an ACE object.
25
+ #
26
+ def initialize(access_mask, ace_type, flags)
27
+ @access_mask = access_mask
28
+ @ace_type = ace_type
29
+ @flags = flags
35
30
  yield self if block_given?
36
31
  end
32
+
33
+ # Returns the type of ace as a string, e.g. "ACCESS_ALLOWED_TYPE_ACE".
34
+ #
35
+ def ace_type_string
36
+ case @ace_type
37
+ when 0x0
38
+ 'ACCESS_ALLOWED_ACE_TYPE'
39
+ when 0x1
40
+ 'ACCESS_DENIED_ACE_TYPE'
41
+ when 0x2
42
+ 'SYSTEM_AUDIT_ACE_TYPE'
43
+ when 0x3
44
+ 'SYSTEM_ALARM_ACE_TYPE'
45
+ when 0x4
46
+ 'ACCESS_ALLOWED_COMPOUND_ACE_TYPE'
47
+ when 0x5
48
+ 'ACCESS_ALLOWED_OBJECT_ACE_TYPE'
49
+ when 0x6
50
+ 'ACCESS_DENIED_OBJECT_ACE_TYPE'
51
+ when 0x7
52
+ 'SYSTEM_AUDIT_OBJECT_ACE_TYPE'
53
+ when 0x8
54
+ 'SYSTEM_ALARM_OBJECT_ACE_TYPE'
55
+ when 0x9
56
+ 'ACCESS_ALLOWED_CALLBACK_ACE_TYPE'
57
+ when 0xA
58
+ 'ACCESS_DENIED_CALLBACK_ACE_TYPE'
59
+ when 0xB
60
+ 'ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE'
61
+ when 0xC
62
+ 'ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE'
63
+ when 0xD
64
+ 'SYSTEM_AUDIT_CALLBACK_ACE_TYPE'
65
+ when 0xE
66
+ 'SYSTEM_ALARM_CALLBACK_ACE_TYPE'
67
+ when 0xF
68
+ 'SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE'
69
+ when 0x10
70
+ 'SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE'
71
+ end
72
+ end
37
73
  end
38
74
  end
39
75
  end
@@ -1,7 +1,3 @@
1
- require File.join(File.dirname(__FILE__), 'windows', 'constants')
2
- require File.join(File.dirname(__FILE__), 'windows', 'structs')
3
- require File.join(File.dirname(__FILE__), 'windows', 'functions')
4
-
5
1
  # The Win32 module serves as a namespace only.
6
2
  module Win32
7
3
 
@@ -28,10 +24,10 @@ module Win32
28
24
  # encapsulates an ACL structure, including a binary representation of
29
25
  # the ACL itself, and the revision information.
30
26
  #
31
- def initialize(revision = ACL_REVISION)
27
+ def initialize(size = 1024, revision = ACL_REVISION)
32
28
  acl = ACL_STRUCT.new
33
29
 
34
- unless InitializeAcl(acl, acl.size, revision)
30
+ unless InitializeAcl(acl, size, revision)
35
31
  raise SystemCallError.new("InitializeAcl", FFI.errno)
36
32
  end
37
33
 
@@ -51,21 +47,87 @@ module Win32
51
47
  info[:AceCount]
52
48
  end
53
49
 
54
- # Adds an access allowed ACE to the given +sid+. The +mask+ is a
55
- # bitwise OR'd value of access rights.
50
+ # Returns a two element array that consists of the bytes in use and
51
+ # bytes free for the ACL.
52
+ #
53
+ def byte_info
54
+ info = ACL_SIZE_INFORMATION.new
55
+
56
+ unless GetAclInformation(@acl, info, info.size, AclSizeInformation)
57
+ raise SystemCallError.new("GetAclInformation", FFI.errno)
58
+ end
59
+
60
+ [info[:AclBytesInUse], info[:AclBytesFree]]
61
+ end
62
+
63
+ # Adds an access allowed ACE to the given +sid+, which can be a
64
+ # Win32::Security::SID object or a plain user or group name. If no
65
+ # sid is provided then the owner of the current process is used.
56
66
  #
57
- # TODO: Move this into the SID class?
58
- def add_access_allowed_ace(sid, mask=0)
59
- unless AddAccessAllowedAce(@acl, @revision, mask, sid)
60
- raise SystemCallError.new("AddAccessAllowedAce", FFI.errno)
67
+ # The +mask+ is a bitwise OR'd value of access rights.
68
+ #
69
+ # The +flags+ argument can be anyone of the following constants.
70
+ #
71
+ # * OBJECT_INHERIT_ACE
72
+ # * CONTAINER_INHERIT_ACE
73
+ # * NO_PROPAGATE_INHERIT_ACE
74
+ # * INHERIT_ONLY_ACE
75
+ # * INHERITED_ACE
76
+ #
77
+ # Example:
78
+ #
79
+ # acl = Win32::Security::ACL.new
80
+ # acl.add_access_allowed_ace('some_user', GENERIC_READ | GENERIC_WRITE)
81
+ #
82
+ def add_access_allowed_ace(sid=nil, mask=0, flags=nil)
83
+ if sid.is_a?(Win32::Security::SID)
84
+ sid = sid.sid
85
+ else
86
+ sid = Win32::Security::SID.new(sid).sid
87
+ end
88
+
89
+ if flags
90
+ unless AddAccessAllowedAceEx(@acl, @revision, flags, mask, sid)
91
+ raise SystemCallError.new("AddAccessAllowedAceEx", FFI.errno)
92
+ end
93
+ else
94
+ unless AddAccessAllowedAce(@acl, @revision, mask, sid)
95
+ raise SystemCallError.new("AddAccessAllowedAce", FFI.errno)
96
+ end
61
97
  end
98
+
99
+ sid
62
100
  end
63
101
 
64
- # Adds an access denied ACE to the given +sid+.
102
+ # Adds an access denied ACE to the given +sid+, which can be a
103
+ # Win32::Security::SID object ora plain user or group name. If
104
+ # no sid is provided then the owner of the current process is used.
105
+ #
106
+ # The +mask+ is the bitwise OR'd value of access rights.
107
+ #
108
+ # The +flags+ argument can be any one of the following constants:
65
109
  #
66
- def add_access_denied_ace(sid, mask=0)
67
- unless AddAccessDeniedAce(@acl, @revision, mask, sid)
68
- raise SystemCallError.new("AddAccessDeniedAce", FFI.errno)
110
+ # * OBJECT_INHERIT_ACE
111
+ # * CONTAINER_INHERIT_ACE
112
+ # * NO_PROPAGATE_INHERIT_ACE
113
+ # * INHERIT_ONLY_ACE
114
+ # * INHERITED_ACE
115
+ #
116
+ def add_access_denied_ace(sid=nil, mask=0, flags=nil)
117
+ if sid.is_a?(Win32::Security::SID)
118
+ sid = sid.sid
119
+ else
120
+ sid = Win32::Security::SID.new(sid).sid
121
+ end
122
+
123
+ if flags
124
+ unless AddAccessDeniedAceEx(@acl, @revision, flags, mask, sid)
125
+ raise SystemCallError.new("AddAccessDeniedAceEx", FFI.errno)
126
+ end
127
+ else
128
+ unless AddAccessDeniedAce(@acl, @revision, mask, sid)
129
+ raise SystemCallError.new("AddAccessDeniedAce", FFI.errno)
130
+ end
69
131
  end
70
132
  end
71
133
 
@@ -74,8 +136,7 @@ module Win32
74
136
  #
75
137
  # Returns the index if successful.
76
138
  #--
77
- # This is untested and will require an actual implementation of
78
- # Win32::Security::Ace before it can work properly.
139
+ # This won't work until we implement the ACE class.
79
140
  #
80
141
  def add_ace(ace, index=MAXDWORD)
81
142
  unless AddAce(@acl, @revision, index, ace, ace.length)
@@ -89,36 +150,49 @@ module Win32
89
150
  # the chain if no index is specified.
90
151
  #
91
152
  # 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
153
  #
96
154
  def delete_ace(index=MAXDWORD)
97
- unless DeleteAce(@ace, index)
155
+ unless DeleteAce(@acl, index)
98
156
  raise SystemCallError.new("DeleteAce", FFI.errno)
99
157
  end
100
158
 
101
159
  index
102
160
  end
103
161
 
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.
162
+ # Finds and returns an ACE object for the ACL at the given
163
+ # +index+. If no index is provided, then it returns an ACE object
164
+ # that corresponds to the first free byte of the ACL.
107
165
  #
108
- def find_ace(index = nil)
109
- pptr = FFI::MemoryPointer.new(:pointer)
110
-
111
- if index.nil?
112
- unless FindFirstFreeAce(@acl, pptr)
113
- raise SystemCallError.new("DeleteAce", FFI.errno)
166
+ # If +raw+ is true, it will return an ACCESS_GENERIC_ACE struct,
167
+ # an FFI object that you can then access directly.
168
+ #
169
+ def find_ace(index = nil, raw = false)
170
+ result = nil
171
+
172
+ FFI::MemoryPointer.new(:pointer) do |pptr|
173
+ if index.nil?
174
+ unless FindFirstFreeAce(@acl, pptr)
175
+ raise SystemCallError.new("FindFirstFreeAce", FFI.errno)
176
+ end
177
+ else
178
+ unless GetAce(@acl, index, pptr)
179
+ raise SystemCallError.new("GetAce", FFI.errno)
180
+ end
114
181
  end
115
- else
116
- unless GetAce(@acl, index, pptr)
117
- raise SystemCallError.new("GetAce", FFI.errno)
182
+
183
+ # There's no way to know what type of ACE it is at this point as far
184
+ # as I know, so we use a generic struct and use the AceType to figure
185
+ # it out later, or the users can.
186
+ ace = ACCESS_GENERIC_ACE.new(pptr.read_pointer)
187
+
188
+ if raw
189
+ result = ace
190
+ else
191
+ result = ACE.new(ace[:Mask], ace[:Header][:AceType], ace[:Header][:AceFlags])
118
192
  end
119
193
  end
120
194
 
121
- pptr.read_pointer.address
195
+ result
122
196
  end
123
197
 
124
198
  # Sets the revision information level, where the +revision_level+
@@ -127,11 +201,12 @@ module Win32
127
201
  # Returns the revision level if successful.
128
202
  #
129
203
  def revision=(revision_level)
130
- buf = FFI::MemoryPointer.new(:ulong)
131
- buf.write_ulong(revision_level)
204
+ FFI::MemoryPointer.new(:ulong) do |buf|
205
+ buf.write_ulong(revision_level)
132
206
 
133
- unless SetAclInformation(@acl, buf, buf.size, AclRevisionInformation)
134
- raise SystemCallError.new("SetAclInformation", FFI.errno)
207
+ unless SetAclInformation(@acl, buf, buf.size, AclRevisionInformation)
208
+ raise SystemCallError.new("SetAclInformation", FFI.errno)
209
+ end
135
210
  end
136
211
 
137
212
  @revision = revision_level
@@ -1,6 +1,3 @@
1
- require File.join(File.dirname(__FILE__), 'windows', 'constants')
2
- require File.join(File.dirname(__FILE__), 'windows', 'functions')
3
- require File.join(File.dirname(__FILE__), 'windows', 'structs')
4
1
  require 'socket'
5
2
 
6
3
  # The Win32 module serves as a namespace only.
@@ -78,27 +75,35 @@ module Win32
78
75
  # Converts a binary SID to a string in S-R-I-S-S... format.
79
76
  #
80
77
  def self.sid_to_string(sid)
81
- string_sid = FFI::MemoryPointer.new(:pointer)
78
+ result = nil
82
79
 
83
- unless ConvertSidToStringSid(sid, string_sid)
84
- raise SystemCallError.new("ConvertSidToStringSid", FFI.errno)
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
85
86
  end
86
87
 
87
- string_sid.read_pointer.read_string
88
+ result
88
89
  end
89
90
 
90
91
  # Converts a string in S-R-I-S-S... format back to a binary SID.
91
92
  #
92
93
  def self.string_to_sid(string)
93
- sid = FFI::MemoryPointer.new(:pointer)
94
+ result = nil
94
95
 
95
- unless ConvertStringSidToSid(string, sid)
96
- raise SystemCallError.new("ConvertStringSidToSid", FFI.errno)
97
- end
96
+ FFI::MemoryPointer.new(:pointer) do |sid|
97
+ unless ConvertStringSidToSid(string, sid)
98
+ raise SystemCallError.new("ConvertStringSidToSid", FFI.errno)
99
+ end
98
100
 
99
- ptr = sid.read_pointer
101
+ ptr = sid.read_pointer
100
102
 
101
- ptr.read_bytes(GetLengthSid(ptr))
103
+ result = ptr.read_bytes(GetLengthSid(ptr))
104
+ end
105
+
106
+ result
102
107
  end
103
108
 
104
109
  # Creates a new SID with +authority+ and up to 8 +subauthorities+,
@@ -127,21 +132,25 @@ module Win32
127
132
  end
128
133
 
129
134
  size = GetSidLengthRequired(sub_authorities.length)
130
- sid = FFI::MemoryPointer.new(:uchar, size)
135
+ new_obj = nil
131
136
 
132
- auth = SID_IDENTIFIER_AUTHORITY.new
133
- auth[:Value][5] = authority
137
+ FFI::MemoryPointer.new(:uchar, size) do |sid|
138
+ auth = SID_IDENTIFIER_AUTHORITY.new
139
+ auth[:Value][5] = authority
134
140
 
135
- unless InitializeSid(sid, auth, sub_authorities.length)
136
- raise SystemCallError.new("InitializeSid", FFI.errno)
137
- end
141
+ unless InitializeSid(sid, auth, sub_authorities.length)
142
+ raise SystemCallError.new("InitializeSid", FFI.errno)
143
+ end
138
144
 
139
- sub_authorities.each_index do |i|
140
- ptr = GetSidSubAuthority(sid, i)
141
- ptr.write_ulong(sub_authorities[i])
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
142
151
  end
143
152
 
144
- new(sid.read_string(size)) # Pass a binary string
153
+ new_obj
145
154
  end
146
155
 
147
156
  # Creates and returns a new Win32::Security::SID object, based on
@@ -182,13 +191,14 @@ module Win32
182
191
  if !bool && FFI.errno != ERROR_NO_TOKEN
183
192
  raise SystemCallError.new("OpenThreadToken", FFI.errno)
184
193
  else
185
- ptoken = FFI::MemoryPointer.new(:uintptr_t)
194
+ ptoken.clear
186
195
  unless OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, ptoken)
187
196
  raise SystemCallError.new("OpenProcessToken", FFI.errno)
188
197
  end
189
198
  end
190
199
 
191
200
  token = ptoken.read_pointer.to_i
201
+
192
202
  pinfo = FFI::MemoryPointer.new(:pointer)
193
203
  plength = FFI::MemoryPointer.new(:ulong)
194
204
 
@@ -196,7 +206,7 @@ module Win32
196
206
  GetTokenInformation(token, 1, pinfo, pinfo.size, plength)
197
207
 
198
208
  pinfo = FFI::MemoryPointer.new(plength.read_ulong)
199
- plength = FFI::MemoryPointer.new(:ulong)
209
+ plength.clear
200
210
 
201
211
  # Second pass, actual call (1 is TokenOwner)
202
212
  unless GetTokenInformation(token, 1, pinfo, pinfo.size, plength)
@@ -241,6 +251,7 @@ module Win32
241
251
  end
242
252
  elsif ordinal_val < 10 # Assume it's a binary SID.
243
253
  account_ptr = FFI::MemoryPointer.from_string(account)
254
+
244
255
  bool = LookupAccountSid(
245
256
  host,
246
257
  account_ptr,
@@ -250,9 +261,12 @@ module Win32
250
261
  domain_size,
251
262
  use_ptr
252
263
  )
264
+
253
265
  unless bool
254
266
  raise SystemCallError.new("LookupAccountSid", FFI.errno)
255
267
  end
268
+
269
+ account_ptr.free
256
270
  else
257
271
  bool = LookupAccountName(
258
272
  host,
@@ -273,11 +287,11 @@ module Win32
273
287
  @sid = token_info.read_string
274
288
  @account = sid.read_string(sid.size).strip
275
289
  elsif ordinal_val < 10
276
- @sid = account
290
+ @sid = account
277
291
  @account = sid.read_string(sid.size).strip
278
292
  else
279
293
  length = GetLengthSid(sid)
280
- @sid = sid.read_string(length)
294
+ @sid = sid.read_string(length)
281
295
  @account = account
282
296
  end
283
297
 
@@ -297,13 +311,17 @@ module Win32
297
311
  # storage or transmission.
298
312
  #
299
313
  def to_s
300
- ptr = FFI::MemoryPointer.new(:pointer)
314
+ string = nil
315
+
316
+ FFI::MemoryPointer.new(:pointer) do |ptr|
317
+ unless ConvertSidToStringSid(@sid, ptr)
318
+ raise SystemCallError.new("ConvertSidToStringSid", FFI.errno)
319
+ end
301
320
 
302
- unless ConvertSidToStringSid(@sid, ptr)
303
- raise SystemCallError.new("ConvertSidToStringSid", FFI.errno)
321
+ string = ptr.read_pointer.read_string
304
322
  end
305
323
 
306
- ptr.read_pointer.read_string
324
+ string
307
325
  end
308
326
 
309
327
  alias to_str to_s
@@ -5,6 +5,7 @@ module Windows
5
5
 
6
6
  TOKEN_QUERY = 8
7
7
  ERROR_NO_TOKEN = 1008
8
+ MAXDWORD = 0xFFFFFFFF
8
9
 
9
10
  # ACL Revisions
10
11
 
@@ -118,6 +119,66 @@ module Windows
118
119
  SidTypeInvalid = 7
119
120
  SidTypeUnknown = 8
120
121
  SidTypeComputer = 9
122
+
123
+ # SDDL version information
124
+
125
+ SDDL_REVISION_1 = 1
126
+
127
+ # ACE flags
128
+
129
+ OBJECT_INHERIT_ACE = 0x1
130
+ CONTAINER_INHERIT_ACE = 0x2
131
+ NO_PROPAGATE_INHERIT_ACE = 0x4
132
+ INHERIT_ONLY_ACE = 0x8
133
+ INHERITED_ACE = 0x10
134
+
135
+ # ACE Types
136
+
137
+ ACCESS_MIN_MS_ACE_TYPE = 0x0
138
+ ACCESS_ALLOWED_ACE_TYPE = 0x0
139
+ ACCESS_DENIED_ACE_TYPE = 0x1
140
+ SYSTEM_AUDIT_ACE_TYPE = 0x2
141
+ SYSTEM_ALARM_ACE_TYPE = 0x3
142
+ ACCESS_MAX_MS_V2_ACE_TYPE = 0x3
143
+ ACCESS_ALLOWED_COMPOUND_ACE_TYPE = 0x4
144
+ ACCESS_MAX_MS_V3_ACE_TYPE = 0x4
145
+ ACCESS_MIN_MS_OBJECT_ACE_TYPE = 0x5
146
+ ACCESS_ALLOWED_OBJECT_ACE_TYPE = 0x5
147
+ ACCESS_DENIED_OBJECT_ACE_TYPE = 0x6
148
+ SYSTEM_AUDIT_OBJECT_ACE_TYPE = 0x7
149
+ SYSTEM_ALARM_OBJECT_ACE_TYPE = 0x8
150
+ ACCESS_MAX_MS_OBJECT_ACE_TYPE = 0x8
151
+ ACCESS_MAX_MS_V4_ACE_TYPE = 0x8
152
+ ACCESS_MAX_MS_ACE_TYPE = 0x8
153
+ ACCESS_ALLOWED_CALLBACK_ACE_TYPE = 0x9
154
+ ACCESS_DENIED_CALLBACK_ACE_TYPE = 0xA
155
+ ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE = 0xB
156
+ ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE = 0xC
157
+ SYSTEM_AUDIT_CALLBACK_ACE_TYPE = 0xD
158
+ SYSTEM_ALARM_CALLBACK_ACE_TYPE = 0xE
159
+ SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE = 0xF
160
+ SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE = 0x10
161
+ ACCESS_MAX_MS_V5_ACE_TYPE = 0x10
162
+
163
+ # Standard Access Rights
164
+
165
+ DELETE = 0x00010000
166
+ READ_CONTROL = 0x20000
167
+ WRITE_DAC = 0x40000
168
+ WRITE_OWNER = 0x80000
169
+ SYNCHRONIZE = 0x100000
170
+ STANDARD_RIGHTS_REQUIRED = 0xf0000
171
+ STANDARD_RIGHTS_READ = 0x20000
172
+ STANDARD_RIGHTS_WRITE = 0x20000
173
+ STANDARD_RIGHTS_EXECUTE = 0x20000
174
+ STANDARD_RIGHTS_ALL = 0x1F0000
175
+ SPECIFIC_RIGHTS_ALL = 0xFFFF
176
+ ACCESS_SYSTEM_SECURITY = 0x1000000
177
+ MAXIMUM_ALLOWED = 0x2000000
178
+ GENERIC_READ = 0x80000000
179
+ GENERIC_WRITE = 0x40000000
180
+ GENERIC_EXECUTE = 0x20000000
181
+ GENERIC_ALL = 0x10000000
121
182
  end
122
183
  end
123
184
  end
@@ -72,14 +72,19 @@ module Windows
72
72
 
73
73
  ffi_lib :advapi32
74
74
 
75
+ attach_pfunc :AddAce, [:ptr, :dword, :dword, :ptr, :dword], :bool
75
76
  attach_pfunc :AddAccessAllowedAce, [:ptr, :dword, :dword, :ptr], :bool
76
- attach_pfunc :AllocateAndInitializeSid,
77
- [:ptr, :int, :dword, :dword, :dword, :dword, :dword, :dword, :dword, :dword, :ptr], :bool
77
+ attach_pfunc :AddAccessAllowedAceEx, [:ptr, :dword, :dword, :dword, :ptr], :bool
78
+ attach_pfunc :AddAccessDeniedAce, [:ptr, :dword, :dword, :ptr], :bool
79
+ attach_pfunc :AddAccessDeniedAceEx, [:ptr, :dword, :dword, :dword, :ptr], :bool
80
+ attach_pfunc :AllocateAndInitializeSid, [:ptr, :int, :dword, :dword, :dword, :dword, :dword, :dword, :dword, :dword, :ptr], :bool
78
81
  attach_pfunc :CheckTokenMembership, [:handle, :ptr, :ptr], :bool
79
82
  attach_pfunc :ConvertSidToStringSid, :ConvertSidToStringSidA, [:ptr, :ptr], :bool
80
83
  attach_pfunc :ConvertStringSidToSid, :ConvertStringSidToSidA, [:string, :ptr], :bool
84
+ attach_pfunc :DeleteAce, [:ptr, :dword], :bool
81
85
  attach_pfunc :EqualSid, [:ptr, :ptr], :bool
82
86
  attach_pfunc :FindFirstFreeAce, [:ptr, :ptr], :bool
87
+ attach_pfunc :GetAce, [:ptr, :dword, :ptr], :bool
83
88
  attach_pfunc :GetAclInformation, [:ptr, :ptr, :dword, :int], :bool
84
89
  attach_pfunc :GetLengthSid, [:ptr], :dword
85
90
  attach_pfunc :GetSidLengthRequired, [:uint], :dword
@@ -90,13 +95,16 @@ module Windows
90
95
  attach_pfunc :IsValidAcl, [:ptr], :bool
91
96
  attach_pfunc :IsValidSid, [:ptr], :bool
92
97
  attach_pfunc :IsWellKnownSid, [:ptr, :int], :bool
93
- attach_pfunc :LookupAccountName, :LookupAccountNameA,
94
- [:string, :string, :ptr, :ptr, :ptr, :ptr, :ptr], :bool
95
- attach_pfunc :LookupAccountSid, :LookupAccountSidA,
96
- [:string, :ptr, :ptr, :ptr, :ptr, :ptr, :ptr], :bool
98
+ attach_pfunc :LookupAccountName, :LookupAccountNameA, [:string, :string, :ptr, :ptr, :ptr, :ptr, :ptr], :bool
99
+ attach_pfunc :LookupAccountSid, :LookupAccountSidA, [:string, :ptr, :ptr, :ptr, :ptr, :ptr, :ptr], :bool
97
100
  attach_pfunc :OpenProcessToken, [:handle, :dword, :ptr], :bool
98
101
  attach_pfunc :OpenThreadToken, [:handle, :dword, :bool, :ptr], :bool
99
102
  attach_pfunc :SetAclInformation, [:ptr, :ptr, :dword, :int], :bool
103
+
104
+ attach_pfunc :ConvertSecurityDescriptorToStringSecurityDescriptor,
105
+ :ConvertSecurityDescriptorToStringSecurityDescriptorA, [:ptr, :dword, :dword, :ptr, :ptr], :bool
106
+ attach_pfunc :ConvertStringSecurityDescriptorToSecurityDescriptor,
107
+ :ConvertStringSecurityDescriptorToSecurityDescriptorA, [:string, :dword, :ptr, :ptr], :bool
100
108
  end
101
109
  end
102
110
  end
@@ -30,6 +30,15 @@ module Windows
30
30
  )
31
31
  end
32
32
 
33
+ # Generic struct we made up and inspect later to determine type.
34
+ class ACCESS_GENERIC_ACE < FFI::Struct
35
+ layout(
36
+ :Header, ACE_HEADER,
37
+ :Mask, :ulong,
38
+ :SidStart, :ulong
39
+ )
40
+ end
41
+
33
42
  class ACCESS_ALLOWED_ACE < FFI::Struct
34
43
  layout(
35
44
  :Header, ACE_HEADER,
@@ -38,6 +47,14 @@ module Windows
38
47
  )
39
48
  end
40
49
 
50
+ class ACCESS_DENIED_ACE < FFI::Struct
51
+ layout(
52
+ :Header, ACE_HEADER,
53
+ :Mask, :ulong,
54
+ :SidStart, :ulong
55
+ )
56
+ end
57
+
41
58
  class ACCESS_ALLOWED_ACE2 < FFI::Struct
42
59
  layout(
43
60
  :Header, ACE_HEADER,
@@ -61,7 +78,15 @@ module Windows
61
78
  layout(
62
79
  :AceCount, :ulong,
63
80
  :AclBytesInUse, :ulong,
64
- :AceBytesFree, :ulong
81
+ :AclBytesFree, :ulong
82
+ )
83
+ end
84
+
85
+ class SECURITY_ATTRIBUTES < FFI::Struct
86
+ layout(
87
+ :nLength, :ulong,
88
+ :lpSecurityDescriptor, :ulong,
89
+ :bInheritHandle, :bool
65
90
  )
66
91
  end
67
92
  end
data/test/test_ace.rb ADDED
@@ -0,0 +1,48 @@
1
+ ########################################################################
2
+ # test_ace.rb
3
+ #
4
+ # Test suite for the Win32::Security::ACE class.
5
+ ########################################################################
6
+ require 'test-unit'
7
+ require 'win32/security'
8
+ require 'win32/security/sid'
9
+ require 'win32/security/acl'
10
+ require 'win32/security/ace'
11
+
12
+ class TC_Win32_Security_Ace < Test::Unit::TestCase
13
+ def setup
14
+ @ace = Win32::Security::ACE.new(1, 1, 1)
15
+ end
16
+
17
+ test "ACE version is set to the expected value" do
18
+ assert_equal('0.1.0', Win32::Security::ACE::VERSION)
19
+ end
20
+
21
+ test "ace_type basic functionality" do
22
+ assert_respond_to(@ace, :ace_type)
23
+ assert_equal(1, @ace.ace_type)
24
+ end
25
+
26
+ test "access_mask basic functionality" do
27
+ assert_respond_to(@ace, :access_mask)
28
+ assert_equal(1, @ace.access_mask)
29
+ end
30
+
31
+ test "flags basic functionality" do
32
+ assert_respond_to(@ace, :flags)
33
+ assert_equal(1, @ace.flags)
34
+ end
35
+
36
+ test "ace_type_string basic functionality" do
37
+ assert_respond_to(@ace, :ace_type_string)
38
+ assert_kind_of(String, @ace.ace_type_string)
39
+ end
40
+
41
+ test "ace_type_string returns the expected value" do
42
+ assert_equal('ACCESS_DENIED_ACE_TYPE', @ace.ace_type_string)
43
+ end
44
+
45
+ def teardown
46
+ @ace = nil
47
+ end
48
+ end
data/test/test_acl.rb CHANGED
@@ -54,11 +54,16 @@ class TC_Win32_Security_Acl < Test::Unit::TestCase
54
54
 
55
55
  test "find_ace basic functionality" do
56
56
  assert_respond_to(@acl, :find_ace)
57
- assert_kind_of(Fixnum, @acl.find_ace)
58
57
  end
59
58
 
60
- test "find_ace returns a sane value" do
61
- assert_true(@acl.find_ace > 1000)
59
+ test "find_ace returns an ACE object if there is one to find" do
60
+ @acl.add_access_allowed_ace('Guest', Win32::Security::ACL::GENERIC_READ)
61
+ assert_kind_of(Win32::Security::ACE, @acl.find_ace)
62
+ end
63
+
64
+ test "find_ace accepts an integer argument" do
65
+ @acl.add_access_allowed_ace('Guest', Win32::Security::ACL::GENERIC_READ)
66
+ assert_kind_of(Win32::Security::ACE, @acl.find_ace(0))
62
67
  end
63
68
 
64
69
  test "revision getter basic functionality" do
@@ -9,7 +9,7 @@ require 'win32/security'
9
9
 
10
10
  class TC_Win32_Security < Test::Unit::TestCase
11
11
  test "version constant is set to expected value" do
12
- assert_equal('0.2.5', Win32::Security::VERSION)
12
+ assert_equal('0.3.0', Win32::Security::VERSION)
13
13
  end
14
14
 
15
15
  test "elevated security basic functionality" do
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'win32-security'
5
- spec.version = '0.2.5'
5
+ spec.version = '0.3.0'
6
6
  spec.authors = ['Daniel J. Berger', 'Park Heesob']
7
7
  spec.license = 'Artistic 2.0'
8
8
  spec.email = 'djberg96@gmail.com'
@@ -12,7 +12,6 @@ Gem::Specification.new do |spec|
12
12
  spec.files = Dir['**/*'].reject{ |f| f.include?('git') }
13
13
 
14
14
  spec.extra_rdoc_files = ['README', 'CHANGES', 'MANIFEST']
15
- spec.rubyforge_project = 'win32utils'
16
15
 
17
16
  spec.add_dependency('ffi')
18
17
 
@@ -22,7 +21,7 @@ Gem::Specification.new do |spec|
22
21
 
23
22
  spec.description = <<-EOF
24
23
  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.
24
+ security related aspects of MS Windows, such as SID's, ACL's and
25
+ ACE's.
27
26
  EOF
28
27
  end
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.2.5
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel J. Berger
@@ -9,68 +9,68 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-02-25 00:00:00.000000000 Z
12
+ date: 2014-10-31 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ffi
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - '>='
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: '0'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - '>='
25
+ - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: rake
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - '>='
32
+ - - ">="
33
33
  - !ruby/object:Gem::Version
34
34
  version: '0'
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - '>='
39
+ - - ">="
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: test-unit
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - '>='
46
+ - - ">="
47
47
  - !ruby/object:Gem::Version
48
48
  version: 2.5.0
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - '>='
53
+ - - ">="
54
54
  - !ruby/object:Gem::Version
55
55
  version: 2.5.0
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: sys-admin
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - '>='
60
+ - - ">="
61
61
  - !ruby/object:Gem::Version
62
62
  version: 1.6.0
63
63
  type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - '>='
67
+ - - ">="
68
68
  - !ruby/object:Gem::Version
69
69
  version: 1.6.0
70
70
  description: |2
71
71
  The win32-security library provides an interface for dealing with
72
- security related aspects of MS Windows. At the moment it provides an
73
- interface for inspecting or creating SID's.
72
+ security related aspects of MS Windows, such as SID's, ACL's and
73
+ ACE's.
74
74
  email: djberg96@gmail.com
75
75
  executables: []
76
76
  extensions: []
@@ -80,16 +80,17 @@ extra_rdoc_files:
80
80
  - MANIFEST
81
81
  files:
82
82
  - CHANGES
83
+ - MANIFEST
84
+ - README
85
+ - Rakefile
86
+ - lib/win32/security.rb
83
87
  - lib/win32/security/ace.rb
84
88
  - lib/win32/security/acl.rb
85
89
  - lib/win32/security/sid.rb
86
90
  - lib/win32/security/windows/constants.rb
87
91
  - lib/win32/security/windows/functions.rb
88
92
  - lib/win32/security/windows/structs.rb
89
- - lib/win32/security.rb
90
- - MANIFEST
91
- - Rakefile
92
- - README
93
+ - test/test_ace.rb
93
94
  - test/test_acl.rb
94
95
  - test/test_security.rb
95
96
  - test/test_sid.rb
@@ -104,21 +105,22 @@ require_paths:
104
105
  - lib
105
106
  required_ruby_version: !ruby/object:Gem::Requirement
106
107
  requirements:
107
- - - '>='
108
+ - - ">="
108
109
  - !ruby/object:Gem::Version
109
110
  version: '0'
110
111
  required_rubygems_version: !ruby/object:Gem::Requirement
111
112
  requirements:
112
- - - '>='
113
+ - - ">="
113
114
  - !ruby/object:Gem::Version
114
115
  version: '0'
115
116
  requirements: []
116
- rubyforge_project: win32utils
117
- rubygems_version: 2.0.3
117
+ rubyforge_project:
118
+ rubygems_version: 2.4.2
118
119
  signing_key:
119
120
  specification_version: 4
120
121
  summary: A library for dealing with aspects of Windows security.
121
122
  test_files:
123
+ - test/test_ace.rb
122
124
  - test/test_acl.rb
123
125
  - test/test_security.rb
124
126
  - test/test_sid.rb