summaryrefslogtreecommitdiff
path: root/libraries
diff options
context:
space:
mode:
authorPaul Morton <pmorton@biaprotect.com>2011-08-05 16:17:29 -0700
committerSeth Chisamore <schisamo@opscode.com>2011-08-10 14:21:29 -0400
commitbf677aef4a723b83752e87d1e60653182477c7e9 (patch)
treee757e4fc3d0765181926e46334deb3f177138f2f /libraries
parentf3de9d593b0471023a0dbf8b4857d3aaa7b07e42 (diff)
downloadmixlib-shellout-bf677aef4a723b83752e87d1e60653182477c7e9.tar.gz
Refactor the registry code into a module
Add windows privileged from dougm Added convience methods in the base Registry::
Diffstat (limited to 'libraries')
-rw-r--r--libraries/registry_helper.rb298
-rw-r--r--libraries/windows_privileged.rb95
2 files changed, 393 insertions, 0 deletions
diff --git a/libraries/registry_helper.rb b/libraries/registry_helper.rb
new file mode 100644
index 0000000..8192a15
--- /dev/null
+++ b/libraries/registry_helper.rb
@@ -0,0 +1,298 @@
+#
+# Author:: Doug MacEachern (<dougm@vmware.com>)
+# Author:: Seth Chisamore (<schisamo@opscode.com>)
+# Author:: Paul Morotn (<pmorton@biaprotect.com>)
+# Cookbook Name:: windows
+# Provider:: registry
+#
+# Copyright:: 2010, VMware, Inc.
+# Copyright:: 2011, Opscode, Inc.
+# Copyright:: 2011, Business Intelligence Associates, Inc
+#
+# 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.
+#
+
+module Windows
+ module RegistryHelper
+ require 'win32/registry'
+ require 'ruby-wmi'
+ @@native_registry_constant = ENV['PROCESSOR_ARCHITEW6432'] == 'AMD64' ? 0x0100 : 0x0200
+
+ def get_hive_name(path)
+ Chef::Log.debug("Resolving registry shortcuts to full names")
+
+ reg_path = path.split("\\")
+ hive_name = reg_path.shift
+
+ hkey = {
+ "HKLM" => "HKEY_LOCAL_MACHINE",
+ "HKCU" => "HKEY_CURRENT_USER",
+ "HKU" => "HKEY_USERS"
+ }[hive_name] || hive_name
+
+ Chef::Log.debug("Hive resolved to #{hkey}")
+ return hkey
+ end
+
+ def get_hive(path)
+
+ Chef::Log.debug("Getting hive for #{path}")
+ reg_path = path.split("\\")
+ hive_name = reg_path.shift
+
+ hkey = get_hive_name(path)
+
+ hive = {
+ "HKEY_LOCAL_MACHINE" => Win32::Registry::HKEY_LOCAL_MACHINE,
+ "HKEY_USERS" => Win32::Registry::HKEY_USERS,
+ "HKEY_CURRENT_USER" => Win32::Registry::HKEY_CURRENT_USER
+ }[hkey]
+
+ unless hive
+ Chef::Application.fatal!("Unsupported registry hive '#{hive_name}'")
+ end
+
+
+ Chef::Log.debug("Registry hive resolved to #{hkey}")
+ return hive
+ end
+
+ def unload_hive(path)
+ hive = get_hive(path)
+ if hive == Win32::Registry::HKEY_USERS
+ reg_path = path.split("\\")
+ priv = Chef::WindowsPrivileged.new
+ begin
+ priv.reg_unload_key(reg_path[1])
+ rescue
+ end
+ end
+ end
+
+ def set_value(mode,path,values)
+ hive, reg_path, hive_name, root_key, hive_loaded = get_reg_path_info(path)
+ key_name = reg_path.join("\\")
+
+ Chef::Log.debug("Registry Mode (#{mode})")
+
+ Chef::Log.debug("Registry Constant #@@native_registry_constant")
+
+ hive.send(mode, key_name, Win32::Registry::KEY_ALL_ACCESS | @@native_registry_constant) do |reg|
+ values.each do |k,val|
+ key = "#{k}" #wtf. avoid "can't modify frozen string" in win32/registry.rb
+ cur_val = nil
+ begin
+ cur_val = reg[key]
+ rescue
+ #subkey does not exist (ok)
+ end
+ if cur_val != val
+ Chef::Log.debug("setting #{key}=#{val}")
+ reg[key] = val
+
+ if(hive_loaded)
+ Chef::Log.debug("Hive was loaded, we really should unload it")
+ unload_hive(path)
+ end
+
+ return true
+ end
+ end
+ end
+ return false
+ end
+
+ def get_value(path,value)
+ hive, reg_path, hive_name, root_key, hive_loaded = get_reg_path_info(path)
+ key = reg_path.join("\\")
+
+ hive.open(key, Win32::Registry::KEY_ALL_ACCESS | @@native_registry_constant) do | reg |
+ begin
+ return reg[value]
+ rescue
+ return nil
+ ensure
+ if(hive_loaded)
+ Chef::Log.debug("Hive was loaded, we really should unload it")
+ unload_hive(path)
+ end
+ end
+ end
+
+
+ end
+
+ def value_exists?(path,value)
+ if key_exists?(path,true)
+
+ hive, reg_path, hive_name, root_key , hive_loaded = get_reg_path_info(path)
+ key = reg_path.join("\\")
+
+ Chef::Log.debug("Attempting to open #{key}");
+ Chef::Log.debug("Native Constant #@@native_registry_constant")
+ Chef::Log.debug("Hive #{hive}")
+
+ hive.open(key, Win32::Registry::KEY_READ | @@native_registry_constant) do | reg |
+ begin
+ rtn_value = reg[value]
+ return true
+ rescue
+ return false
+ ensure
+ if(hive_loaded)
+ Chef::Log.debug("Hive was loaded, we really should unload it")
+ unload_hive(path)
+ end
+ end
+ end
+
+ end
+ return false
+ end
+
+ # TODO: Does not load user registry...
+ def key_exists?(path, load_hive = false)
+ if load_hive
+ hive, reg_path, hive_name, root_key , hive_loaded = get_reg_path_info(path)
+ key = reg_path.join("\\")
+ else
+ hive = get_hive(path)
+ reg_path = path.split("\\")
+ hive_name = reg_path.shift
+ root_key = reg_path[0]
+ key = reg_path.join("\\")
+ hive_loaded = false
+ end
+
+
+ begin
+ hive.open(key, Win32::Registry::Constants::KEY_READ | @@native_registry_constant )
+ return true
+ rescue
+ return false
+ ensure
+ if(hive_loaded)
+ Chef::Log.debug("Hive was loaded, we really should unload it")
+ unload_hive(path)
+ end
+ end
+ end
+
+ def get_user_hive_location(sid)
+ reg_key = "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\#{sid}"
+ Chef::Log.debug("Looking for profile at #{reg_key}")
+ if key_exists?(reg_key)
+ return get_value(reg_key,'ProfileImagePath')
+ else
+ return nil
+ end
+
+ end
+
+ def resolve_user_to_sid(username)
+ begin
+ sid = WMI::Win32_UserAccount.find(:first, :conditions => {:name => username}).sid
+ Chef::Log.debug("Resolved user SID to #{sid}")
+ return sid
+ rescue
+ return nil
+ end
+ end
+
+ def hive_loaded?(path)
+ hive = get_hive(path)
+ reg_path = path.split("\\")
+ hive_name = reg_path.shift
+ user_hive = path[0]
+
+ if is_user_hive?(hive)
+ return key_exists?("#{hive_name}\\#{user_hive}")
+ else
+ return true
+ end
+ end
+
+ def is_user_hive?(hive)
+ if hive == Win32::Registry::HKEY_USERS
+ return true
+ else
+ return true
+ end
+ end
+
+ def get_reg_path_info(path)
+ hive = get_hive(path)
+ reg_path = path.split("\\")
+ hive_name = reg_path.shift
+ root_key = reg_path[0]
+ hive_loaded = false
+
+ if is_user_hive?(hive) && !key_exists?("#{hive_name}\\#{root_key}")
+ reg_path, hive_loaded = load_user_hive(hive,reg_path,root_key)
+ root_key = reg_path[0]
+ Chef::Log.debug("Resolved user (#{path}) to (#{reg_path.join('/')})")
+ end
+
+ return hive, reg_path, hive_name, root_key, hive_loaded
+ end
+
+ def load_user_hive(hive,reg_path,user_hive)
+ Chef::Log.debug("Reg Path #{reg_path}")
+ # See if the hive is loaded. Logged in users will have a key that is named their SID
+ # if the user has specified the a path by SID and the user is logged in, this function
+ # should not be executed.
+ if is_user_hive?(hive) && !key_exists?("HKU\\#{user_hive}")
+ Chef::Log.debug("The user is not logged in and has not been specified by SID")
+ sid = resolve_user_to_sid(user_hive)
+ Chef::Log.debug("User SID resolved to (#{sid})")
+ # Now that the user has been resolved to a SID, check and see if the hive exists.
+ # If this exists by SID, the user is logged in and we should use that key.
+ # TODO: Replace the username with the sid and send it back because the username
+ # does not exist as the key location.
+ load_reg = false
+ if key_exists?("HKU\\#{sid}")
+ reg_path[0] = sid #use the active profile (user is logged on)
+ Chef::Log.debug("HKEY_USERS Mapped: #{user_hive} -> #{sid}")
+ else
+ Chef::Log.debug("User is not logged in")
+ load_reg = true
+ end
+
+ # The user is not logged in, so we should load the registry from disk
+ if load_reg
+ profile_path = get_user_hive_location(sid)
+ if profile_path != nil
+ ntuser_dat = "#{profile_path}\\NTUSER.DAT"
+ if ::File.exists?(ntuser_dat)
+ priv = Chef::WindowsPrivileged.new
+ if priv.reg_load_key(sid,ntuser_dat)
+ Chef::Log.debug("RegLoadKey(#{sid}, #{user_hive}, #{ntuser_dat})")
+ reg_path[0] = sid
+
+ else
+ Chef::Log.debug("Failed RegLoadKey(#{sid}, #{user_hive}, #{ntuser_dat})")
+ end
+ end
+ end
+ end
+ end
+
+ return reg_path, load_reg
+
+ end
+ end
+end
+
+class Registry
+ extend Windows::RegistryHelper
+end \ No newline at end of file
diff --git a/libraries/windows_privileged.rb b/libraries/windows_privileged.rb
new file mode 100644
index 0000000..fc26a08
--- /dev/null
+++ b/libraries/windows_privileged.rb
@@ -0,0 +1,95 @@
+#
+# Cookbook Name:: windows
+# Library:: windows_privileged
+# Author:: Doug MacEachern <dougm@vmware.com>
+# Author:: Paul Morton (<pmorton@biaprotect.com>)
+#
+# Copyright 2010, VMware, Inc.
+# Copyright:: 2011, Business Intelligence Associates, Inc
+#
+# 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.
+#
+
+#helpers for Windows API calls that require privilege adjustments
+class Chef
+ class WindowsPrivileged
+
+ #XXX can we tell Chef not to load this library unless on Windows?
+ if RUBY_PLATFORM =~ /mswin|mingw32|windows/
+ require 'windows/error'
+ require 'windows/registry'
+ require 'windows/process'
+ require 'windows/security'
+
+ include Windows::Error
+ include Windows::Registry
+ include Windows::Process
+ include Windows::Security
+ end
+
+ #File -> Load Hive... in regedit.exe
+ def reg_load_key(name, file)
+ run(SE_BACKUP_NAME, SE_RESTORE_NAME) do
+ rc = RegLoadKey(HKEY_USERS, "#{name}", file)
+ if rc == ERROR_SUCCESS
+ return true
+ elsif rc == ERROR_SHARING_VIOLATION
+ return false
+ else
+ raise get_last_error(rc)
+ end
+ end
+ end
+
+ #File -> Unload Hive... in regedit.exe
+ def reg_unload_key(name)
+ run(SE_BACKUP_NAME, SE_RESTORE_NAME) do
+ rc = RegUnLoadKey(HKEY_USERS, "#{name}")
+ if rc != ERROR_SUCCESS
+ raise get_last_error(rc)
+ end
+ end
+ end
+
+ def run(*privileges)
+ token = [0].pack('L')
+
+ unless OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, token)
+ raise get_last_error
+ end
+ token = token.unpack('L')[0]
+
+ privileges.each do |name|
+ unless adjust_privilege(token, name, SE_PRIVILEGE_ENABLED)
+ raise get_last_error
+ end
+ end
+
+ begin
+ yield
+ ensure #disable privs
+ privileges.each do |name|
+ adjust_privilege(token, name, 0)
+ end
+ end
+ end
+
+ def adjust_privilege(token, priv, attr=0)
+ luid = [0,0].pack('Ll')
+ if LookupPrivilegeValue(nil, priv, luid)
+ new_state = [1, luid.unpack('Ll'), attr].flatten.pack('LLlL')
+ AdjustTokenPrivileges(token, 0, new_state, new_state.size, 0, 0)
+ end
+ end
+ end
+end \ No newline at end of file