summaryrefslogtreecommitdiff
path: root/lib/chef/win32/security
diff options
context:
space:
mode:
authorSeth Chisamore <schisamo@opscode.com>2012-10-30 10:39:35 -0400
committerSeth Chisamore <schisamo@opscode.com>2012-10-30 10:39:35 -0400
commit24dc69a9a97e82a6e4207de68d6dcc664178249b (patch)
tree19bb289c9f88b4bbab066bc56b95d6d222fd5c35 /lib/chef/win32/security
parent9348c1c9c80ee757354d624b7dc1b78ebc7605c4 (diff)
downloadchef-24dc69a9a97e82a6e4207de68d6dcc664178249b.tar.gz
[OC-3564] move core Chef to the repo root \o/ \m/
The opscode/chef repository now only contains the core Chef library code used by chef-client, knife and chef-solo!
Diffstat (limited to 'lib/chef/win32/security')
-rw-r--r--lib/chef/win32/security/ace.rb125
-rw-r--r--lib/chef/win32/security/acl.rb101
-rw-r--r--lib/chef/win32/security/securable_object.rb109
-rw-r--r--lib/chef/win32/security/security_descriptor.rb93
-rw-r--r--lib/chef/win32/security/sid.rb199
-rw-r--r--lib/chef/win32/security/token.rb64
6 files changed, 691 insertions, 0 deletions
diff --git a/lib/chef/win32/security/ace.rb b/lib/chef/win32/security/ace.rb
new file mode 100644
index 0000000000..efd44b1c85
--- /dev/null
+++ b/lib/chef/win32/security/ace.rb
@@ -0,0 +1,125 @@
+#
+# 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'
+require 'chef/win32/security/sid'
+require 'chef/win32/memory'
+
+require 'ffi'
+
+class Chef
+ module ReservedNames::Win32
+ class Security
+ class ACE
+
+ def initialize(pointer, owner = nil)
+ if Chef::ReservedNames::Win32::API::Security::ACE_WITH_MASK_AND_SID.supports?(pointer.read_uchar)
+ @struct = Chef::ReservedNames::Win32::API::Security::ACE_WITH_MASK_AND_SID.new pointer
+ else
+ # TODO Support ALL the things
+ @struct = Chef::ReservedNames::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)
+ Chef::ReservedNames::Win32::API::Security::ACE_WITH_MASK_AND_SID.offset_of(:SidStart) + sid.size
+ end
+
+ def self.access_allowed(sid, mask, flags = 0)
+ create_ace_with_mask_and_sid(Chef::ReservedNames::Win32::API::Security::ACCESS_ALLOWED_ACE_TYPE, flags, mask, sid)
+ end
+
+ def self.access_denied(sid, mask, flags = 0)
+ create_ace_with_mask_and_sid(Chef::ReservedNames::Win32::API::Security::ACCESS_DENIED_ACE_TYPE, flags, mask, sid)
+ end
+
+ attr_reader :struct
+
+ def ==(other)
+ type == other.type && flags == other.flags && mask == other.mask && sid == other.sid
+ end
+
+ def dup
+ ACE.create_ace_with_mask_and_sid(type, flags, mask, sid)
+ end
+
+ def flags
+ struct[:AceFlags]
+ end
+
+ def flags=(val)
+ struct[:AceFlags] = val
+ end
+
+ def explicit?
+ ! inherited?
+ end
+
+ def inherited?
+ (struct[:AceFlags] & Chef::ReservedNames::Win32::API::Security::INHERITED_ACE) != 0
+ end
+
+ def mask
+ struct[:Mask]
+ end
+
+ def mask=(val)
+ struct[:Mask] = val
+ end
+
+ def pointer
+ struct.pointer
+ end
+
+ def size
+ struct[:AceSize]
+ end
+
+ def sid
+ # The SID runs off the end of the structure, starting at :SidStart.
+ # Use pointer arithmetic to get a pointer to that location.
+ Chef::ReservedNames::Win32::Security::SID.new(struct.pointer + struct.offset_of(:SidStart))
+ end
+
+ def to_s
+ "#{sid.account_name}/flags:#{flags.to_s(16)}/mask:#{mask.to_s(16)}"
+ end
+
+ def type
+ struct[:AceType]
+ end
+
+ private
+
+ 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 = Chef::ReservedNames::Win32::API::Security::ACE_WITH_MASK_AND_SID.new pointer
+ struct[:AceType] = type
+ struct[:AceFlags] = flags
+ struct[:AceSize] = size_needed
+ struct[:Mask] = mask
+ Chef::ReservedNames::Win32::Memory.memcpy(struct.pointer + struct.offset_of(:SidStart), sid.pointer, sid.size)
+ ACE.new(struct.pointer)
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/lib/chef/win32/security/acl.rb b/lib/chef/win32/security/acl.rb
new file mode 100644
index 0000000000..fd43b75cbf
--- /dev/null
+++ b/lib/chef/win32/security/acl.rb
@@ -0,0 +1,101 @@
+#
+# 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'
+require 'chef/win32/security/ace'
+require 'ffi'
+
+class Chef
+ module ReservedNames::Win32
+ class Security
+ class ACL
+ include Enumerable
+
+ def initialize(pointer, owner = nil)
+ @struct = Chef::ReservedNames::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
+ end
+
+ def self.create(aces)
+ aces_size = aces.inject(0) { |sum,ace| sum + ace.size }
+ acl_size = align_dword(Chef::ReservedNames::Win32::API::Security::ACLStruct.size + aces_size) # What the heck is 94???
+ acl = Chef::ReservedNames::Win32::Security.initialize_acl(acl_size)
+ aces.each { |ace| Chef::ReservedNames::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)
+ Chef::ReservedNames::Win32::Security.get_ace(self, index)
+ end
+
+ def delete_at(index)
+ Chef::ReservedNames::Win32::Security.delete_ace(self, index)
+ end
+
+ def each
+ 0.upto(length-1) { |i| yield self[i] }
+ end
+
+ def insert(index, *aces)
+ aces.reverse_each { |ace| add_ace(self, ace, index) }
+ end
+
+ def length
+ struct[:AceCount]
+ end
+
+ def push(*aces)
+ aces.each { |ace| Chef::ReservedNames::Win32::Security.add_ace(self, ace) }
+ end
+
+ def unshift(*aces)
+ aces.each { |ace| Chef::ReservedNames::Win32::Security.add_ace(self, ace, 0) }
+ end
+
+ def valid?
+ Chef::ReservedNames::Win32::Security.is_valid_acl(self)
+ end
+
+ def to_s
+ "[#{self.collect { |ace| ace.to_s }.join(", ")}]"
+ end
+ private
+
+ def self.align_dword(size)
+ (size + 4 - 1) & 0xfffffffc
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/win32/security/securable_object.rb b/lib/chef/win32/security/securable_object.rb
new file mode 100644
index 0000000000..00655c9bab
--- /dev/null
+++ b/lib/chef/win32/security/securable_object.rb
@@ -0,0 +1,109 @@
+#
+# 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'
+require 'chef/win32/security/acl'
+require 'chef/win32/security/sid'
+
+class Chef
+ module ReservedNames::Win32
+ class Security
+ class SecurableObject
+
+ def initialize(path, type = :SE_FILE_OBJECT)
+ @path = path
+ @type = type
+ end
+
+ attr_reader :path
+ attr_reader :type
+
+ SecurityConst = Chef::ReservedNames::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::ReservedNames::Win32::API::Security::STANDARD_RIGHTS_READ if (mask | Chef::ReservedNames::Win32::API::Security::GENERIC_READ) != 0
+ #mask |= Chef::ReservedNames::Win32::API::Security::STANDARD_RIGHTS_WRITE if (mask | Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE) != 0
+ #mask |= Chef::ReservedNames::Win32::API::Security::STANDARD_RIGHTS_EXECUTE if (mask | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE) != 0
+ #mask |= Chef::ReservedNames::Win32::API::Security::STANDARD_RIGHTS_ALL if (mask | Chef::ReservedNames::Win32::API::Security::GENERIC_ALL) != 0
+ if type == :SE_FILE_OBJECT
+ mask |= Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ if (mask & Chef::ReservedNames::Win32::API::Security::GENERIC_READ) != 0
+ mask |= Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE if (mask & Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE) != 0
+ mask |= Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE if (mask & Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE) != 0
+ mask |= Chef::ReservedNames::Win32::API::Security::FILE_ALL_ACCESS if (mask & Chef::ReservedNames::Win32::API::Security::GENERIC_ALL) != 0
+ else
+ raise "Unimplemented object type for predict_security_mask: #{type}"
+ end
+ mask &= ~(Chef::ReservedNames::Win32::API::Security::GENERIC_READ | Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE | Chef::ReservedNames::Win32::API::Security::GENERIC_ALL)
+ mask
+ end
+
+ def security_descriptor(include_sacl = false)
+ security_information = Chef::ReservedNames::Win32::API::Security::OWNER_SECURITY_INFORMATION | Chef::ReservedNames::Win32::API::Security::GROUP_SECURITY_INFORMATION | Chef::ReservedNames::Win32::API::Security::DACL_SECURITY_INFORMATION
+ if include_sacl
+ security_information |= Chef::ReservedNames::Win32::API::Security::SACL_SECURITY_INFORMATION
+ Security.with_privileges("SeSecurityPrivilege") do
+ Security.get_named_security_info(path, type, security_information)
+ end
+ else
+ Security.get_named_security_info(path, type, security_information)
+ end
+ end
+
+ def 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)
+ Security.set_named_security_info(path, type, :dacl => dacl, :dacl_inherits => dacl_inherits)
+ end
+
+ def group=(val)
+ Security.set_named_security_info(path, type, :group => val)
+ end
+
+ def owner=(val)
+ # TODO to fix serious permissions problems, we may need to enable SeBackupPrivilege. But we might need it (almost) everywhere else, too.
+ Security.with_privileges("SeTakeOwnershipPrivilege", "SeRestorePrivilege") do
+ Security.set_named_security_info(path, type, :owner => val)
+ end
+ end
+
+ def sacl=(val)
+ Security.with_privileges("SeSecurityPrivilege") do
+ Security.set_named_security_info(path, type, :sacl => val)
+ end
+ end
+
+ def set_sacl(sacl, sacl_inherits)
+ Security.with_privileges("SeSecurityPrivilege") do
+ Security.set_named_security_info(path, type, :sacl => sacl, :sacl_inherits => sacl_inherits)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/win32/security/security_descriptor.rb b/lib/chef/win32/security/security_descriptor.rb
new file mode 100644
index 0000000000..658e9104b4
--- /dev/null
+++ b/lib/chef/win32/security/security_descriptor.rb
@@ -0,0 +1,93 @@
+#
+# 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'
+require 'chef/win32/security/acl'
+require 'chef/win32/security/sid'
+
+class Chef
+ module ReservedNames::Win32
+ class Security
+ class SecurityDescriptor
+
+ def initialize(pointer)
+ @pointer = pointer
+ end
+
+ attr_reader :pointer
+
+ def absolute?
+ !self_relative?
+ end
+
+ def control
+ control, version = Chef::ReservedNames::Win32::Security.get_security_descriptor_control(self)
+ control
+ end
+
+ def dacl
+ raise "DACL not present" if !dacl_present?
+ present, acl, defaulted = Chef::ReservedNames::Win32::Security.get_security_descriptor_dacl(self)
+ acl
+ end
+
+ def dacl_inherits?
+ (control & Chef::ReservedNames::Win32::API::Security::SE_DACL_PROTECTED) == 0
+ end
+
+ def dacl_present?
+ (control & Chef::ReservedNames::Win32::API::Security::SE_DACL_PRESENT) != 0
+ end
+
+ def group
+ result, defaulted = Chef::ReservedNames::Win32::Security.get_security_descriptor_group(self)
+ result
+ end
+
+ def owner
+ result, defaulted = Chef::ReservedNames::Win32::Security.get_security_descriptor_owner(self)
+ result
+ end
+
+ def sacl
+ raise "SACL not present" if !sacl_present?
+ Security.with_privileges("SeSecurityPrivilege") do
+ present, acl, defaulted = Chef::ReservedNames::Win32::Security.get_security_descriptor_sacl(self)
+ acl
+ end
+ end
+
+ def sacl_inherits?
+ (control & Chef::ReservedNames::Win32::API::Security::SE_SACL_PROTECTED) == 0
+ end
+
+ def sacl_present?
+ (control & Chef::ReservedNames::Win32::API::Security::SE_SACL_PRESENT) != 0
+ end
+
+ def self_relative?
+ (control & Chef::ReservedNames::Win32::API::Security::SE_SELF_RELATIVE) != 0
+ end
+
+ def valid?
+ Chef::ReservedNames::Win32::Security.is_valid_security_descriptor(self)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/win32/security/sid.rb b/lib/chef/win32/security/sid.rb
new file mode 100644
index 0000000000..7ca21eee79
--- /dev/null
+++ b/lib/chef/win32/security/sid.rb
@@ -0,0 +1,199 @@
+#
+# 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
+ module ReservedNames::Win32
+ class Security
+ class SID
+
+ def initialize(pointer, owner = nil)
+ @pointer = pointer
+ # Keep a reference to the actual owner of this memory so we don't get freed
+ @owner = owner
+ end
+
+ def self.from_account(name)
+ domain, sid, use = Chef::ReservedNames::Win32::Security.lookup_account_name(name)
+ sid
+ end
+
+ def self.from_string_sid(string_sid)
+ Chef::ReservedNames::Win32::Security::convert_string_sid_to_sid(string_sid)
+ end
+
+ def ==(other)
+ other != nil && Chef::ReservedNames::Win32::Security.equal_sid(self, other)
+ end
+
+ attr_reader :pointer
+
+ def account
+ Chef::ReservedNames::Win32::Security.lookup_account_sid(self)
+ end
+
+ def account_name
+ domain, name, use = account
+ (domain != nil && domain.length > 0) ? "#{domain}\\#{name}" : name
+ end
+
+ def size
+ Chef::ReservedNames::Win32::Security.get_length_sid(self)
+ end
+
+ def to_s
+ Chef::ReservedNames::Win32::Security.convert_sid_to_string_sid(self)
+ end
+
+ def valid?
+ Chef::ReservedNames::Win32::Security.is_valid_sid(self)
+ end
+
+ # Well-known SIDs
+ def self.Null
+ SID.from_string_sid('S-1-0')
+ end
+ def self.Nobody
+ SID.from_string_sid('S-1-0-0')
+ end
+ def self.World
+ SID.from_string_sid('S-1-1')
+ end
+ def self.Everyone
+ SID.from_string_sid('S-1-1-0')
+ end
+ def self.Local
+ SID.from_string_sid('S-1-2')
+ end
+ def self.Creator
+ SID.from_string_sid('S-1-3')
+ end
+ def self.CreatorOwner
+ SID.from_string_sid('S-1-3-0')
+ end
+ def self.CreatorGroup
+ SID.from_string_sid('S-1-3-1')
+ end
+ def self.CreatorOwnerServer
+ SID.from_string_sid('S-1-3-2')
+ end
+ def self.CreatorGroupServer
+ SID.from_string_sid('S-1-3-3')
+ end
+ def self.NonUnique
+ SID.from_string_sid('S-1-4')
+ end
+ def self.Nt
+ SID.from_string_sid('S-1-5')
+ end
+ def self.Dialup
+ SID.from_string_sid('S-1-5-1')
+ end
+ def self.Network
+ SID.from_string_sid('S-1-5-2')
+ end
+ def self.Batch
+ SID.from_string_sid('S-1-5-3')
+ end
+ def self.Interactive
+ SID.from_string_sid('S-1-5-4')
+ end
+ def self.Service
+ SID.from_string_sid('S-1-5-6')
+ end
+ def self.Anonymous
+ SID.from_string_sid('S-1-5-7')
+ end
+ def self.Proxy
+ SID.from_string_sid('S-1-5-8')
+ end
+ def self.EnterpriseDomainControllers
+ SID.from_string_sid('S-1-5-9')
+ end
+ def self.PrincipalSelf
+ SID.from_string_sid('S-1-5-10')
+ end
+ def self.AuthenticatedUsers
+ SID.from_string_sid('S-1-5-11')
+ end
+ def self.RestrictedCode
+ SID.from_string_sid('S-1-5-12')
+ end
+ def self.TerminalServerUsers
+ SID.from_string_sid('S-1-5-13')
+ end
+ def self.LocalSystem
+ SID.from_string_sid('S-1-5-18')
+ end
+ def self.NtLocal
+ SID.from_string_sid('S-1-5-19')
+ end
+ def self.NtNetwork
+ SID.from_string_sid('S-1-5-20')
+ end
+ def self.BuiltinAdministrators
+ SID.from_string_sid('S-1-5-32-544')
+ end
+ def self.BuiltinUsers
+ SID.from_string_sid('S-1-5-32-545')
+ end
+ def self.Guests
+ SID.from_string_sid('S-1-5-32-546')
+ end
+ def self.PowerUsers
+ SID.from_string_sid('S-1-5-32-547')
+ end
+ def self.AccountOperators
+ SID.from_string_sid('S-1-5-32-548')
+ end
+ def self.ServerOperators
+ SID.from_string_sid('S-1-5-32-549')
+ end
+ def self.PrintOperators
+ SID.from_string_sid('S-1-5-32-550')
+ end
+ def self.BackupOperators
+ SID.from_string_sid('S-1-5-32-551')
+ end
+ def self.Replicators
+ SID.from_string_sid('S-1-5-32-552')
+ end
+ def self.Administrators
+ SID.from_string_sid('S-1-5-32-544')
+ end
+
+ # Machine-specific, well-known SIDs
+ # TODO: don't use strings, dummy
+ def self.None
+ SID.from_account("#{::ENV['COMPUTERNAME']}\\None")
+ end
+ def self.Administrator
+ SID.from_account("#{::ENV['COMPUTERNAME']}\\Administrator")
+ end
+ def self.Guest
+ SID.from_account("#{::ENV['COMPUTERNAME']}\\Guest")
+ end
+
+ def self.current_user
+ SID.from_account("#{::ENV['USERDOMAIN']}\\#{::ENV['USERNAME']}")
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/lib/chef/win32/security/token.rb b/lib/chef/win32/security/token.rb
new file mode 100644
index 0000000000..ded4fc080e
--- /dev/null
+++ b/lib/chef/win32/security/token.rb
@@ -0,0 +1,64 @@
+#
+# 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'
+require 'chef/win32/api/security'
+
+require 'ffi'
+
+class Chef
+ module ReservedNames::Win32
+ class Security
+ class Token
+
+ def initialize(handle)
+ @handle = handle
+ end
+
+ attr_reader :handle
+
+ def enable_privileges(*privilege_names)
+ # Build the list of privileges we want to set
+ new_privileges = Chef::ReservedNames::Win32::API::Security::TOKEN_PRIVILEGES.new(
+ FFI::MemoryPointer.new(Chef::ReservedNames::Win32::API::Security::TOKEN_PRIVILEGES.size_with_privileges(privilege_names.length)))
+ new_privileges[:PrivilegeCount] = 0
+ privilege_names.each do |privilege_name|
+ luid = Chef::ReservedNames::Win32::API::Security::LUID.new
+ # Ignore failure (with_privileges TRIES but does not guarantee success--
+ # APIs down the line will fail if privilege escalation fails)
+ if Chef::ReservedNames::Win32::API::Security.LookupPrivilegeValueW(nil, privilege_name.to_wstring, luid)
+ new_privilege = new_privileges.privilege(new_privileges[:PrivilegeCount])
+ new_privilege[:Luid][:LowPart] = luid[:LowPart]
+ new_privilege[:Luid][:HighPart] = luid[:HighPart]
+ new_privilege[:Attributes] = Chef::ReservedNames::Win32::API::Security::SE_PRIVILEGE_ENABLED
+ new_privileges[:PrivilegeCount] = new_privileges[:PrivilegeCount] + 1
+ end
+ end
+
+ old_privileges = Chef::ReservedNames::Win32::Security.adjust_token_privileges(self, new_privileges)
+ end
+
+ def adjust_privileges(privileges_struct)
+ if privileges_struct[:PrivilegeCount] > 0
+ Chef::ReservedNames::Win32::Security::adjust_token_privileges(self, privileges_struct)
+ end
+ end
+ end
+ end
+ end
+end