win32-security 0.2.5 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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