summaryrefslogtreecommitdiff
path: root/chef
diff options
context:
space:
mode:
authorJohn Keiser <jkeiser@opscode.com>2011-11-21 01:02:58 -0800
committerSeth Chisamore <schisamo@opscode.com>2011-12-08 20:10:57 -0500
commit7feea09feb5bc7a095692af0a7d0b81376c95e3a (patch)
treecdacba3bb093015320bc9d1a8911235765e4f057 /chef
parent983b8796dbf71afb285ef4abbe749814386ec1b0 (diff)
downloadchef-7feea09feb5bc7a095692af0a7d0b81376c95e3a.tar.gz
Add Win32FileAccessControl, make security work again
Diffstat (limited to 'chef')
-rw-r--r--chef/lib/chef/win32/api/error.rb44
-rw-r--r--chef/lib/chef/win32/api/security.rb8
-rw-r--r--chef/lib/chef/win32/security.rb14
-rw-r--r--chef/lib/chef/win32/security/ace.rb29
-rw-r--r--chef/lib/chef/win32/security/acl.rb30
-rw-r--r--chef/lib/chef/win32/security/securable_object.rb50
-rw-r--r--chef/lib/chef/win32/security/security_descriptor.rb26
-rw-r--r--chef/lib/chef/win32/security/sid.rb12
-rw-r--r--chef/lib/chef/win32_file_access_control.rb118
9 files changed, 261 insertions, 70 deletions
diff --git a/chef/lib/chef/win32/api/error.rb b/chef/lib/chef/win32/api/error.rb
index 9ab961adf6..7553a18593 100644
--- a/chef/lib/chef/win32/api/error.rb
+++ b/chef/lib/chef/win32/api/error.rb
@@ -870,6 +870,50 @@ class Chef
SEM_NOGPFAULTERRORBOX = 0x0002
SEM_NOOPENFILEERRORBOX = 0x8000
+ def IS_ERROR(status)
+ status >> 31 == 1
+ end
+
+ def MAKE_HRESULT(sev, fac, code)
+ sev << 31 | fac << 16 | code
+ end
+
+ def MAKE_SCODE(sev, fac, code)
+ sev << 31 | fac << 16 | code
+ end
+
+ def HRESULT_CODE(hr)
+ hr & 0xFFFF
+ end
+
+ def HRESULT_FACILITY(hr)
+ (hr >> 16) & 0x1fff
+ end
+
+ def HRESULT_FROM_NT(x)
+ x | 0x10000000 # FACILITY_NT_BIT
+ end
+
+ def HRESULT_FROM_WIN32(x)
+ if x <= 0
+ x
+ else
+ (x & 0x0000FFFF) | (7 << 16) | 0x80000000
+ end
+ end
+
+ def HRESULT_SEVERITY(hr)
+ (hr >> 31) & 0x1
+ end
+
+ def FAILED(status)
+ status < 0
+ end
+
+ def SUCCEEDED(status)
+ status >= 0
+ end
+
# Functions
=begin
DWORD WINAPI FormatMessage(
diff --git a/chef/lib/chef/win32/api/security.rb b/chef/lib/chef/win32/api/security.rb
index 7a46eddac1..9d571ecf9c 100644
--- a/chef/lib/chef/win32/api/security.rb
+++ b/chef/lib/chef/win32/api/security.rb
@@ -225,10 +225,10 @@ class Chef
# The AceTypes this structure supports
def self.supports?(ace_type)
[
- Win::Security::ACCESS_ALLOWED_ACE_TYPE,
- Win::Security::ACCESS_DENIED_ACE_TYPE,
- Win::Security::SYSTEM_AUDIT_ACE_TYPE,
- Win::Security::SYSTEM_ALARM_ACE_TYPE
+ ACCESS_ALLOWED_ACE_TYPE,
+ ACCESS_DENIED_ACE_TYPE,
+ SYSTEM_AUDIT_ACE_TYPE,
+ SYSTEM_ALARM_ACE_TYPE
].include?(ace_type)
end
end
diff --git a/chef/lib/chef/win32/security.rb b/chef/lib/chef/win32/security.rb
index 6362567836..da3587e432 100644
--- a/chef/lib/chef/win32/security.rb
+++ b/chef/lib/chef/win32/security.rb
@@ -26,6 +26,7 @@ class Chef
class Security
class << self
+ include Chef::Win32::API::Error
include Chef::Win32::API::Security
#
@@ -104,7 +105,7 @@ class Chef
def get_named_security_info(path, type = :SE_FILE_OBJECT, info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION)
security_descriptor = FFI::MemoryPointer.new :pointer
hr = GetNamedSecurityInfoW(path.to_wstring, type, info, nil, nil, nil, nil, security_descriptor)
- if hr != :S_OK
+ if FAILED(hr)
Chef::Win32::Error.raise!
end
@@ -177,7 +178,7 @@ class Chef
def initialize_acl(acl_size)
acl = FFI::MemoryPointer.new acl_size
- unless Win::Security::InitializeAcl(acl, acl_size, ACL_REVISION)
+ unless InitializeAcl(acl, acl_size, ACL_REVISION)
Chef::Win32::Error.raise!
end
ACL.new(acl)
@@ -213,7 +214,7 @@ class Chef
system_name = system_name.to_wstring if system_name
if LookupAccountNameW(system_name, name.to_wstring, nil, sid_size, nil, referenced_domain_name_size, nil)
raise "Expected ERROR_INSUFFICIENT_BUFFER from LookupAccountName, and got no error!"
- elsif get_last_error != ERROR_INSUFFICIENT_BUFFER
+ elsif Chef::Win32::Error.get_last_error != ERROR_INSUFFICIENT_BUFFER
Chef::Win32::Error.raise!
end
@@ -232,9 +233,10 @@ class Chef
# Figure out how big the buffer needs to be
name_size = FFI::Buffer.new(:long).write_long(0)
referenced_domain_name_size = FFI::Buffer.new(:long).write_long(0)
- if LookupAccountSidW(system_name.to_wstring, sid, nil, name_size, nil, referenced_domain_name_size, nil)
+ system_name = system_name.to_wstring if system_name
+ if LookupAccountSidW(system_name, sid, nil, name_size, nil, referenced_domain_name_size, nil)
raise "Expected ERROR_INSUFFICIENT_BUFFER from LookupAccountSid, and got no error!"
- elsif get_last_error != ERROR_INSUFFICIENT_BUFFER
+ elsif Chef::Win32::Error::get_last_error != ERROR_INSUFFICIENT_BUFFER
Chef::Win32::Error.raise!
end
@@ -312,7 +314,7 @@ class Chef
end
hr = SetNamedSecurityInfoW(path.to_wstring, type, security_information, owner, group, dacl, sacl)
- if hr != :S_OK
+ if FAILED(hr)
Chef::Win32::Error.raise!
end
end
diff --git a/chef/lib/chef/win32/security/ace.rb b/chef/lib/chef/win32/security/ace.rb
index 6800c06ead..326b77fc45 100644
--- a/chef/lib/chef/win32/security/ace.rb
+++ b/chef/lib/chef/win32/security/ace.rb
@@ -24,37 +24,38 @@ require 'ffi'
class Chef
module Win32
- module Security
+ class Security
class ACE
- include Chef::Win32::Memory
- include Chef::Win32::Security
-
def initialize(pointer, owner = nil)
- if ACE_WITH_MASK_AND_SID.supports?(pointer.read_uchar)
- @struct = ACE_WITH_MASK_AND_SID.new pointer
+ if Chef::Win32::API::Security::ACE_WITH_MASK_AND_SID.supports?(pointer.read_uchar)
+ @struct = Chef::Win32::API::Security::ACE_WITH_MASK_AND_SID.new pointer
else
# TODO Support ALL the things
- @struct = ACE_HEADER.new pointer
+ @struct = Chef::Win32::API::Security::ACE_HEADER.new pointer
end
# Keep a reference to the actual owner of this memory so we don't get freed
@owner = owner
end
def self.size_with_sid(sid)
- ACE_WITH_MASK_AND_SID.offset_of(:SidStart) + sid.size
+ Chef::Win32::API::Security::ACE_WITH_MASK_AND_SID.offset_of(:SidStart) + sid.size
end
def self.access_allowed(sid, access_mask, flags = 0)
- create_ace_with_mask_and_sid(ACCESS_ALLOWED_ACE_TYPE, flags, access_mask, sid)
+ create_ace_with_mask_and_sid(Chef::Win32::API::Security::ACCESS_ALLOWED_ACE_TYPE, flags, access_mask, sid)
end
def self.access_denied(sid, access_mask, flags = 0)
- create_ace_with_mask_and_sid(ACCESS_DENIED_ACE_TYPE, flags, access_mask, sid)
+ create_ace_with_mask_and_sid(Chef::Win32::API::Security::ACCESS_DENIED_ACE_TYPE, flags, access_mask, sid)
end
attr_reader :struct
+ def ==(other)
+ type == other.type && flags == other.flags && access_mask == other.access_mask && sid == other.sid
+ end
+
def flags
struct[:AceFlags]
end
@@ -68,7 +69,7 @@ class Chef
end
def inherited?
- (struct[:AceFlags] & INHERITED_ACE) != 0
+ (struct[:AceFlags] & Chef::Win32::API::Security::INHERITED_ACE) != 0
end
def mask
@@ -90,7 +91,7 @@ class Chef
def sid
# The SID runs off the end of the structure, starting at :SidStart.
# Use pointer arithmetic to get a pointer to that location.
- SID.new(struct.pointer + struct.offset_of(:SidStart))
+ Chef::Win32::Security::SID.new(struct.pointer + struct.offset_of(:SidStart))
end
def type
@@ -102,12 +103,12 @@ class Chef
def self.create_ace_with_mask_and_sid(type, flags, mask, sid)
size_needed = size_with_sid(sid)
pointer = FFI::MemoryPointer.new size_needed
- struct = ACE_WITH_MASK_AND_SID.new pointer
+ struct = Chef::Win32::API::Security::ACE_WITH_MASK_AND_SID.new pointer
struct[:AceType] = type
struct[:AceFlags] = flags
struct[:AceSize] = size_needed
struct[:Mask] = mask
- memcpy(struct.pointer + struct.offset_of(:SidStart), sid.pointer, sid.size)
+ Chef::Win32::Memory.memcpy(struct.pointer + struct.offset_of(:SidStart), sid.pointer, sid.size)
ACE.new(struct.pointer)
end
end
diff --git a/chef/lib/chef/win32/security/acl.rb b/chef/lib/chef/win32/security/acl.rb
index 66cf560804..0a5d2eafd7 100644
--- a/chef/lib/chef/win32/security/acl.rb
+++ b/chef/lib/chef/win32/security/acl.rb
@@ -22,14 +22,12 @@ require 'ffi'
class Chef
module Win32
- module Security
+ class Security
class ACL
include Enumerable
- include Chef::Win32::Security
-
def initialize(pointer, owner = nil)
- @struct = :ACLStruct.new pointer
+ @struct = Chef::Win32::API::Security::ACLStruct.new pointer
# Keep a reference to the actual owner of this memory so that it isn't freed out from under us
# TODO this could be avoided if we could mark a pointer's parent manually
@owner = owner
@@ -37,24 +35,32 @@ class Chef
def self.create(aces)
aces_size = aces.inject(0) { |sum,ace| sum + ace.size }
- acl_size = align_dword(ACLStruct.size + aces_size) # What the heck is 94???
- acl = initialize_acl(acl_size)
- aces.each { |ace| add_ace(acl, ace) }
+ acl_size = align_dword(Chef::Win32::API::Security::ACLStruct.size + aces_size) # What the heck is 94???
+ acl = Chef::Win32::Security.initialize_acl(acl_size)
+ aces.each { |ace| Chef::Win32::Security.add_ace(acl, ace) }
acl
end
attr_reader :struct
+ def ==(other)
+ return false if length != other.length
+ 0.upto(length-1) do |i|
+ return false if self[i] != other[i]
+ end
+ return true
+ end
+
def pointer
struct.pointer
end
def [](index)
- get_ace(self, index)
+ Chef::Win32::Security.get_ace(self, index)
end
def delete_at(index)
- delete_ace(self, index)
+ Chef::Win32::Security.delete_ace(self, index)
end
def each
@@ -70,15 +76,15 @@ class Chef
end
def push(*aces)
- aces.each { |ace| add_ace(self, ace) }
+ aces.each { |ace| Chef::Win32::Security.add_ace(self, ace) }
end
def unshift(*aces)
- aces.each { |ace| add_ace(self, ace, 0) }
+ aces.each { |ace| Chef::Win32::Security.add_ace(self, ace, 0) }
end
def valid?
- is_valid_acl(self)
+ Chef::Win32::Security.is_valid_acl(self)
end
private
diff --git a/chef/lib/chef/win32/security/securable_object.rb b/chef/lib/chef/win32/security/securable_object.rb
index 5a57f0291a..06744a6c7b 100644
--- a/chef/lib/chef/win32/security/securable_object.rb
+++ b/chef/lib/chef/win32/security/securable_object.rb
@@ -22,49 +22,73 @@ require 'chef/win32/security/sid'
class Chef
module Win32
- module Security
+ class Security
class SecurableObject
- include Chef::Win32::Security
-
def initialize(path, type = :SE_FILE_OBJECT)
@path = path
@type = type
end
- attr_reader :pointer
+ attr_reader :path
+ attr_reader :type
+
+ SecurityConst = Chef::Win32::API::Security
+
+ # This method predicts what the rights mask would be on an object
+ # if you created an ACE with the given mask. Specifically, it looks for
+ # generic attributes like GENERIC_READ, and figures out what specific
+ # attributes will be set. This is important if you want to try to
+ # compare an existing ACE with one you want to create.
+ def predict_rights_mask(generic_mask)
+ mask = generic_mask
+ #mask |= Chef::Win32::API::Security::STANDARD_RIGHTS_READ if (mask | Chef::Win32::API::Security::GENERIC_READ) != 0
+ #mask |= Chef::Win32::API::Security::STANDARD_RIGHTS_WRITE if (mask | Chef::Win32::API::Security::GENERIC_WRITE) != 0
+ #mask |= Chef::Win32::API::Security::STANDARD_RIGHTS_EXECUTE if (mask | Chef::Win32::API::Security::GENERIC_EXECUTE) != 0
+ #mask |= Chef::Win32::API::Security::STANDARD_RIGHTS_ALL if (mask | Chef::Win32::API::Security::GENERIC_ALL) != 0
+ if type == :SE_FILE_OBJECT
+ mask |= Chef::Win32::API::Security::FILE_GENERIC_READ if (mask & Chef::Win32::API::Security::GENERIC_READ) != 0
+ mask |= Chef::Win32::API::Security::FILE_GENERIC_WRITE if (mask & Chef::Win32::API::Security::GENERIC_WRITE) != 0
+ mask |= Chef::Win32::API::Security::FILE_GENERIC_EXECUTE if (mask & Chef::Win32::API::Security::GENERIC_EXECUTE) != 0
+ mask |= Chef::Win32::API::Security::FILE_ALL_ACCESS if (mask & Chef::Win32::API::Security::GENERIC_ALL) != 0
+ else
+ raise "Unimplemented object type for predict_security_mask: #{type}"
+ end
+ mask &= ~(Chef::Win32::API::Security::GENERIC_READ | Chef::Win32::API::Security::GENERIC_WRITE | Chef::Win32::API::Security::GENERIC_EXECUTE | Chef::Win32::API::Security::GENERIC_ALL)
+ mask
+ end
def security_descriptor(include_sacl = false)
- security_information = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION
- security_information |= SACL_SECURITY_INFORMATION if include_sacl
- get_named_security_info(@path, @type, security_information)
+ security_information = Chef::Win32::API::Security::OWNER_SECURITY_INFORMATION | Chef::Win32::API::Security::GROUP_SECURITY_INFORMATION | Chef::Win32::API::Security::DACL_SECURITY_INFORMATION
+ security_information |= Chef::Win32::API::Security::SACL_SECURITY_INFORMATION if include_sacl
+ Security.get_named_security_info(path, type, security_information)
end
def dacl=(val)
- set_named_security_info(@path, @type, :dacl => val)
+ Security.set_named_security_info(path, type, :dacl => val)
end
# You don't set dacl_inherits without also setting dacl,
# because Windows gets angry and denies you access. So
# if you want to do that, you may as well do both at once.
def set_dacl(dacl, dacl_inherits)
- set_named_security_info(@path, @type, :dacl => dacl, :dacl_inherits => dacl_inherits)
+ Security.set_named_security_info(path, type, :dacl => dacl, :dacl_inherits => dacl_inherits)
end
def group=(val)
- set_named_security_info(@path, @type, :group => val)
+ Security.set_named_security_info(path, type, :group => val)
end
def owner=(val)
- set_named_security_info(@path, @type, :owner => val)
+ Security.set_named_security_info(path, type, :owner => val)
end
def sacl=(val)
- set_named_security_info(@path, @type, :sacl => val)
+ Security.set_named_security_info(path, type, :sacl => val)
end
def set_sacl(sacl, sacl_inherits)
- set_named_security_info(@path, @type, :sacl => sacl, :sacl_inherits => sacl_inherits)
+ Security.set_named_security_info(path, type, :sacl => sacl, :sacl_inherits => sacl_inherits)
end
end
end
diff --git a/chef/lib/chef/win32/security/security_descriptor.rb b/chef/lib/chef/win32/security/security_descriptor.rb
index c7ac9ce035..43a9cfe04c 100644
--- a/chef/lib/chef/win32/security/security_descriptor.rb
+++ b/chef/lib/chef/win32/security/security_descriptor.rb
@@ -22,11 +22,9 @@ require 'chef/win32/security/sid'
class Chef
module Win32
- module Security
+ class Security
class SecurityDescriptor
- include Chef::Win32::Security
-
def initialize(pointer)
@pointer = pointer
end
@@ -38,54 +36,54 @@ class Chef
end
def control
- control, version = get_security_descriptor_control(self)
+ control, version = Chef::Win32::Security.get_security_descriptor_control(self)
control
end
def dacl
raise "DACL not present" if !dacl_present?
- present, acl, defaulted = get_security_descriptor_dacl(self)
+ present, acl, defaulted = Chef::Win32::Security.get_security_descriptor_dacl(self)
acl
end
def dacl_inherits?
- (control & SE_DACL_PROTECTED) == 0
+ (control & Chef::Win32::API::Security::SE_DACL_PROTECTED) == 0
end
def dacl_present?
- (control & SE_DACL_PRESENT) != 0
+ (control & Chef::Win32::API::Security::SE_DACL_PRESENT) != 0
end
def group
- result, defaulted = get_security_descriptor_group(self)
+ result, defaulted = Chef::Win32::Security.get_security_descriptor_group(self)
result
end
def owner
- result, defaulted = get_security_descriptor_owner(self)
+ result, defaulted = Chef::Win32::Security.get_security_descriptor_owner(self)
result
end
def sacl
raise "SACL not present" if !sacl_present?
- present, acl, defaulted = get_security_descriptor_sacl(self)
+ present, acl, defaulted = Chef::Win32::Security.get_security_descriptor_sacl(self)
acl
end
def sacl_inherits?
- (control & SE_SACL_PROTECTED) == 0
+ (control & Chef::Win32::API::Security::SE_SACL_PROTECTED) == 0
end
def sacl_present?
- (control & SE_SACL_PRESENT) != 0
+ (control & Chef::Win32::API::Security::SE_SACL_PRESENT) != 0
end
def self_relative?
- (control & SE_SELF_RELATIVE) != 0
+ (control & Chef::Win32::API::Security::SE_SELF_RELATIVE) != 0
end
def valid?
- is_valid_security_descriptor(self)
+ Chef::Win32::Security.is_valid_security_descriptor(self)
end
end
end
diff --git a/chef/lib/chef/win32/security/sid.rb b/chef/lib/chef/win32/security/sid.rb
index b0ee6f4e41..8fe54d9460 100644
--- a/chef/lib/chef/win32/security/sid.rb
+++ b/chef/lib/chef/win32/security/sid.rb
@@ -20,11 +20,9 @@ require 'chef/win32/security'
class Chef
module Win32
- module Security
+ class Security
class SID
- include Chef::Win32::Security
-
def initialize(pointer, owner = nil)
@pointer = pointer
# Keep a reference to the actual owner of this memory so we don't get freed
@@ -32,14 +30,14 @@ class Chef
end
def self.from_account(name)
- domain, sid, use = lookup_account_name(name)
+ domain, sid, use = Chef::Win32::Security.lookup_account_name(name)
sid
end
attr_reader :pointer
def account
- lookup_account_sid(self)
+ Chef::Win32::Security.lookup_account_sid(self)
end
def account_name
@@ -48,11 +46,11 @@ class Chef
end
def size
- get_length_sid(self)
+ Chef::Win32::Security.get_length_sid(self)
end
def valid?
- is_valid_sid(self)
+ Chef::Win32::Security.is_valid_sid(self)
end
end
end
diff --git a/chef/lib/chef/win32_file_access_control.rb b/chef/lib/chef/win32_file_access_control.rb
new file mode 100644
index 0000000000..4d74b0d6ee
--- /dev/null
+++ b/chef/lib/chef/win32_file_access_control.rb
@@ -0,0 +1,118 @@
+#
+# Author:: John Keiser (<jkeiser@opscode.com>)
+# Copyright:: Copyright 2011 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/win32/security'
+
+class Chef
+ class Win32FileAccessControl
+ include Chef::Win32::API::Security
+
+ def self.apply_security_policy(resource, securable_object)
+ provider = Win32FileAccessControl.new(resource, securable_object)
+ provider.apply_security_policy()
+ end
+
+ def apply_security_policy
+ existing = securable_object.security_descriptor
+ # Apply owner and group
+ if existing.owner != target_owner
+ puts "Changing owner from #{existing.owner.account_name} to #{target_owner.account_name}"
+ securable_object.owner = target_owner
+ end
+ if existing.group != target_group
+ puts "Changing group from #{existing.group.account_name} to #{target_group.account_name}"
+ securable_object.group = target_group
+ end
+
+ # Apply DACL and inherits
+ target_dacl = build_target_dacl
+ if existing.dacl_inherits? != target_inherits
+ puts "Changing DACL and inherits"
+ securable_object.set_dacl(target_dacl, target_inherits)
+ elsif !acls_equal(target_dacl, existing.dacl)
+ puts "Changing DACL"
+ securable_object.dacl = target_dacl
+ end
+ end
+
+ private
+
+ def initialize(resource, securable_object)
+ @resource = resource
+ @securable_object = securable_object
+ end
+
+ attr_reader :resource
+ attr_reader :securable_object
+
+ Security = Chef::Win32::Security
+ ACE = Security::ACE
+
+ def acls_equal(target_acl, actual_acl)
+ return false if target_acl.length != actual_acl.length
+ 0.upto(target_acl.length - 1) do |i|
+ target_ace = a[i]
+ actual_ace = b[i]
+ return false if target_ace.sid != actual_ace.sid
+ return false if target_ace.flags != actual_ace.flags
+ return false if securable_object.predict_rights_mask(target_ace.mask) != actual_ace.mask
+ end
+ end
+
+ def target_inherits
+ resource.inherits == nil ? true : resource.inherits
+ end
+
+ def target_owner
+ get_sid(resource.owner)
+ end
+
+ def target_group
+ get_sid(resource.group)
+ end
+
+ def build_target_dacl
+ acls = []
+ resource.rights.each_pair do |type, users|
+ case type
+ when :deny
+ users.each { |user| acls.push ACE.access_denied(get_sid(user), GENERIC_ALL) }
+ when :read
+ users.each { |user| acls.push(ACE.access_allowed(get_sid(user), GENERIC_READ | GENERIC_EXECUTE)) }
+ when :write
+ users.each { |user| acls.push(ACE.access_allowed(get_sid(user), GENERIC_WRITE | GENERIC_READ | GENERIC_EXECUTE)) }
+ when :full
+ users.each { |user| acls.push(ACE.access_allowed(get_sid(user), GENERIC_ALL)) }
+ else
+ raise "Unknown rights type #{type}"
+ end
+ end
+ Chef::Win32::Security::ACL.create(acls)
+ end
+
+ def get_sid(value)
+ if value.kind_of?(String)
+ Chef::Win32::Security::SID.from_account(value)
+ elsif value.kind_of?(Chef::Win32::Security::SID)
+ value
+ else
+ raise "Must specify username, group or SID: #{value}"
+ end
+ end
+ end
+end \ No newline at end of file