inspec/lib/resources/registry_key.rb
Adam Leff 577688a3a0 Placing all resources in the Inspec::Resources namespace
Many of the resources are named as a top-level class with a fairly generic class name, such as "OS". This causes an issue specifically with kitchen-google which depends on a gem which depends on the "os" gem which itself defines an OS class with a different superclass. This prevents users from using TK, Google Compute, and Inspec without this fix.

Some mocked commands had their digest changed as well due to the new indentation, specifically in the User and RegistryKey classes.

I strongly recommend viewing this diff with `git diff --ignore-space-change`
to see the *real* changes. :)
2016-03-08 13:40:16 -05:00

185 lines
5.4 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# encoding: utf-8
# copyright: 2015, Vulcano Security GmbH
# author: Christoph Hartmann
# license: All rights reserved
require 'json'
# Usage:
# describe registry_key('Task Scheduler','HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Schedule') do
# its('Start') { should eq 2 }
# end
module Inspec::Resources
class RegistryKey < Inspec.resource(1)
name 'registry_key'
desc 'Use the registry_key InSpec audit resource to test key values in the Microsoft Windows registry.'
example "
describe registry_key('path\to\key') do
its('name') { should eq 'value' }
end
"
attr_accessor :reg_key
def initialize(name, reg_key = nil)
# if we have one parameter, we use it as name
reg_key ||= name
@name = name
@reg_key = reg_key
return skip_resource 'The `registry_key` resource is not supported on your OS yet.' if !inspec.os.windows?
end
def exists?
!registry_key(@reg_key).nil?
end
def has_value?(value)
val = registry_key(@reg_key)
!val.nil? && registry_property_value(val, '(default)') == value ? true : false
end
def has_property?(property_name, property_type = nil)
val = registry_key(@reg_key)
!val.nil? && registry_property_exists(val, property_name) && (property_type.nil? || registry_property_type(val, property_name) == map2type(property_type)) ? true : false
end
# deactivate rubocop, because we need to stay compatible with Serverspe
# rubocop:disable Style/OptionalArguments
def has_property_value?(property_name, property_type = nil, value)
# rubocop:enable Style/OptionalArguments
val = registry_key(@reg_key)
# convert value to binary if required
value = value.bytes if !property_type.nil? && map2type(property_type) == 3 && !value.is_a?(Array)
!val.nil? && registry_property_value(val, property_name) == value && (property_type.nil? || registry_property_type(val, property_name) == map2type(property_type)) ? true : false
end
# returns nil, if not existant or value
def method_missing(meth)
# get data
val = registry_key(@reg_key)
registry_property_value(val, meth)
end
def to_s
"Registry Key #{@name}"
end
private
def prep_prop(property)
property.to_s.downcase
end
def registry_property_exists(regkey, property)
return false if regkey.nil? || property.nil?
# always ensure the key is lower case
!regkey[prep_prop(property)].nil?
end
def registry_property_value(regkey, property)
return nil if !registry_property_exists(regkey, property)
# always ensure the key is lower case
regkey[prep_prop(property)]['value']
end
def registry_property_type(regkey, property)
return nil if !registry_property_exists(regkey, property)
# always ensure the key is lower case
regkey[prep_prop(property)]['type']
end
def registry_key(path)
return @registry_cache if defined?(@registry_cache)
# load registry key and all properties
script = <<-EOH
$reg = Get-Item 'Registry::#{path}'
$object = New-Object -Type PSObject
$reg.Property | ForEach-Object {
$key = $_
if ("(default)".Equals($key)) { $key = '' }
$value = New-Object psobject -Property @{
"value" = $reg.GetValue($key);
"type" = $reg.GetValueKind($key);
}
$object | Add-Member MemberType NoteProperty Name $_ Value $value
}
$object | ConvertTo-Json
EOH
cmd = inspec.script(script)
# cannot rely on exit code for now, successful command returns exit code 1
# return nil if cmd.exit_status != 0, try to parse json
begin
@registry_cache = JSON.parse(cmd.stdout)
# convert keys to lower case
@registry_cache = Hash[@registry_cache.map do |key, value|
[key.downcase, value]
end]
rescue JSON::ParserError => _e
@registry_cache = nil
end
@registry_cache
end
# Registry key value types
# @see https://msdn.microsoft.com/en-us/library/windows/desktop/ms724884(v=vs.85).aspx
# REG_NONE 0
# REG_SZ 1
# REG_EXPAND_SZ 2
# REG_BINARY 3
# REG_DWORD 4
# REG_DWORD_LITTLE_ENDIAN 4
# REG_DWORD_BIG_ENDIAN 5
# REG_LINK 6
# REG_MULTI_SZ 7
# REG_RESOURCE_LIST 8
# REG_FULL_RESOURCE_DESCRIPTOR 9
# REG_RESOURCE_REQUIREMENTS_LIST 10
# REG_QWORD 11
# REG_QWORD_LITTLE_ENDIAN 11
def map2type(symbol)
options = {}
# chef symbols, we prefer those
options[:binary] = 3
options[:string] = 1
options[:multi_string] = 7
options[:expand_string] = 2
options[:dword] = 4
options[:dword_big_endian] = 5
options[:qword] = 11
# serverspec symbols
options[:type_string] = 1
options[:type_binary] = 3
options[:type_dword] = 4
options[:type_qword] = 11
options[:type_multistring] = 7
options[:type_expandstring] = 2
options[symbol]
end
end
# for compatability with serverspec
# this is deprecated syntax and will be removed in future versions
class WindowsRegistryKey < RegistryKey
name 'windows_registry_key'
def initialize(name)
deprecated
super(name)
end
def deprecated
warn '[DEPRECATION] `windows_registry_key(reg_key)` is deprecated. Please use `registry_key(\'path\to\key\')` instead.'
end
end
end