summaryrefslogtreecommitdiff
path: root/lib/chef
diff options
context:
space:
mode:
authorJohn Keiser <jkeiser@opscode.com>2013-10-15 20:41:52 -0700
committerJohn Keiser <jkeiser@opscode.com>2013-10-15 20:41:52 -0700
commite1c6bef68597f5c4f418107ef9e3638e44cc8cf7 (patch)
treec6871e3dcded48265f2b82c26ab13cd62a0ba2be /lib/chef
parent2da5abd0648f3ba6977d3a69d858078237bee585 (diff)
downloadchef-e1c6bef68597f5c4f418107ef9e3638e44cc8cf7.tar.gz
Add --config-file-jail to avoid loading user knife.rb in tests
Diffstat (limited to 'lib/chef')
-rw-r--r--lib/chef/application.rb51
-rw-r--r--lib/chef/application/client.rb5
-rw-r--r--lib/chef/chef_fs/config.rb10
-rw-r--r--lib/chef/chef_fs/path_utils.rb5
-rw-r--r--lib/chef/config.rb9
-rw-r--r--lib/chef/knife.rb12
6 files changed, 75 insertions, 17 deletions
diff --git a/lib/chef/application.rb b/lib/chef/application.rb
index ca9cfff291..2987f58839 100644
--- a/lib/chef/application.rb
+++ b/lib/chef/application.rb
@@ -25,6 +25,8 @@ require 'chef/platform'
require 'mixlib/cli'
require 'tmpdir'
require 'rbconfig'
+require 'pathname'
+require 'chef/chef_fs/path_utils'
class Chef::Application
include Mixlib::CLI
@@ -75,7 +77,21 @@ class Chef::Application
# Parse the config file
def load_config_file
if !config[:config_file]
- Chef::Log.warn("No config file found or specified on command line, not loading.")
+ Chef::Log.warn("No config file found or specified on command line, using command line options.")
+ Chef::Config.merge!(config)
+ return
+ end
+
+ if !Chef::Application.config_file_exists?(config[:config_file])
+ Chef::Log.warn("*****************************************")
+ if !File.exists?(config[:config_file])
+ Chef::Log.warn("Did not find config file: #{config[:config_file]}, using command line options.")
+ else
+ Chef::Log.warn("Config file #{config[:config_file]} not inside the jail #{Chef::Config.config_file_jail}, using command line options.", 2)
+ end
+ Chef::Log.warn("*****************************************")
+
+ Chef::Config.merge!(config)
return
end
@@ -86,12 +102,6 @@ class Chef::Application
else
::File::open(config[:config_file]) { |f| apply_config(f.path) }
end
- rescue Errno::ENOENT => error
- Chef::Log.warn("*****************************************")
- Chef::Log.warn("Did not find config file: #{config[:config_file]}, using command line options.")
- Chef::Log.warn("*****************************************")
-
- Chef::Config.merge!(config)
rescue SocketError => error
Chef::Application.fatal!("Error getting config file #{config[:config_file]}", 2)
rescue Chef::Exceptions::ConfigurationError => error
@@ -101,6 +111,33 @@ class Chef::Application
end
end
+ # Determines whether a config file exists, taking into account file existence
+ # as well as Chef::Config.config_file_jail (if they are not under the jail,
+ # this method will return false). Takes symlinks and relative paths into
+ # account.
+ def self.config_file_exists?(config_file)
+ if config_file =~ /^(http|https):\/\//
+ return true
+ end
+
+ begin
+ real_config_file = Pathname.new(config_file).realpath.to_s
+ rescue Errno::ENOENT
+ return false
+ end
+
+ return true if !Chef::Config.config_file_jail
+
+ begin
+ jail = Pathname.new(Chef::Config.config_file_jail).realpath.to_s
+ rescue Errno::ENOENT
+ Chef::Log.warn("Config file jail #{Chef::Config.config_file_jail} does not exist: will not load any config file.")
+ return false
+ end
+
+ Chef::ChefFS::PathUtils.descendant_of?(real_config_file, jail)
+ end
+
# Initialize and configure the logger.
# === Loggers and Formatters
# In Chef 10.x and previous, the Logger was the primary/only way that Chef
diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb
index ea8d599b4c..0964101fad 100644
--- a/lib/chef/application/client.rb
+++ b/lib/chef/application/client.rb
@@ -206,6 +206,10 @@ class Chef::Application::Client < Chef::Application
:long => "--chef-zero-port PORT",
:description => "Port to start chef-zero on"
+ option :config_file_jail,
+ :long => "--config-file-jail PATH",
+ :description => "Directory under which config files are allowed to be loaded (no client.rb or knife.rb outside this path will be loaded)."
+
if Chef::Platform.windows?
option :fatal_windows_admin_check,
:short => "-A",
@@ -272,6 +276,7 @@ class Chef::Application::Client < Chef::Application
end
def load_config_file
+ Chef::Config.config_file_jail = config[:config_file_jail] if config[:config_file_jail]
if !config.has_key?(:config_file)
if config[:local_mode]
require 'chef/knife'
diff --git a/lib/chef/chef_fs/config.rb b/lib/chef/chef_fs/config.rb
index bfbe379775..e08b976961 100644
--- a/lib/chef/chef_fs/config.rb
+++ b/lib/chef/chef_fs/config.rb
@@ -84,16 +84,14 @@ class Chef
# If the path does not reach into ANY specified directory, nil is returned.
def server_path(file_path)
pwd = File.expand_path(Dir.pwd)
- absolute_path = Chef::ChefFS::PathUtils.realest_path(File.expand_path(file_path, pwd))
+ absolute_pwd = Chef::ChefFS::PathUtils.realest_path(File.expand_path(file_path, pwd))
# Check all object paths (cookbooks_dir, data_bags_dir, etc.)
object_paths.each_pair do |name, paths|
paths.each do |path|
realest_path = Chef::ChefFS::PathUtils.realest_path(path)
- if absolute_path[0,realest_path.length] == realest_path &&
- (absolute_path.length == realest_path.length ||
- absolute_path[realest_path.length,1] =~ /#{PathUtils.regexp_path_separator}/)
- relative_path = Chef::ChefFS::PathUtils::relative_to(absolute_path, realest_path)
+ if PathUtils.descendant_of?(absolute_pwd, realest_path)
+ relative_path = Chef::ChefFS::PathUtils::relative_to(absolute_pwd, realest_path)
return relative_path == '.' ? "/#{name}" : "/#{name}/#{relative_path}"
end
end
@@ -102,7 +100,7 @@ class Chef
# Check chef_repo_path
Array(@chef_config[:chef_repo_path]).flatten.each do |chef_repo_path|
realest_chef_repo_path = Chef::ChefFS::PathUtils.realest_path(chef_repo_path)
- if absolute_path == realest_chef_repo_path
+ if absolute_pwd == realest_chef_repo_path
return '/'
end
end
diff --git a/lib/chef/chef_fs/path_utils.rb b/lib/chef/chef_fs/path_utils.rb
index 805b092b3a..9ef75ce2e5 100644
--- a/lib/chef/chef_fs/path_utils.rb
+++ b/lib/chef/chef_fs/path_utils.rb
@@ -82,6 +82,11 @@ class Chef
end
end
+ def self.descendant_of?(path, ancestor)
+ path[0,ancestor.length] == ancestor &&
+ (ancestor.length == path.length || path[ancestor.length,1] =~ /#{PathUtils.regexp_path_separator}/)
+ end
+
def self.is_absolute?(path)
path =~ /^#{regexp_path_separator}/
end
diff --git a/lib/chef/config.rb b/lib/chef/config.rb
index 0a4ee6e94c..f2610f01e2 100644
--- a/lib/chef/config.rb
+++ b/lib/chef/config.rb
@@ -73,6 +73,13 @@ class Chef
formatters << [name, file_path]
end
+ # Config file to load (client.rb, knife.rb, etc. defaults set differently in knife, chef-client, etc.)
+ configurable(:config_file)
+
+ # No config file (client.rb / knife.rb / etc.) will be loaded outside this path.
+ # Major use case is tests, where we don't want to load the user's config files.
+ configurable(:config_file_jail)
+
default :formatters, []
# Override the config dispatch to set the value of multiple server options simultaneously
@@ -215,6 +222,8 @@ class Chef
# An array of paths to search for knife exec scripts if they aren't in the current directory
default :script_path, []
+ # The root of all caches (checksums, cache and backup). If local mode is on,
+ # this is under the user's home directory.
default(:cache_path) do
if local_mode
"#{user_home}#{platform_path_separator}.chef#{platform_path_separator}local-mode-cache"
diff --git a/lib/chef/knife.rb b/lib/chef/knife.rb
index 5ff6b92643..dbb719c30a 100644
--- a/lib/chef/knife.rb
+++ b/lib/chef/knife.rb
@@ -335,8 +335,7 @@ class Chef
end
candidate_configs.each do | candidate_config |
- candidate_config = File.expand_path(candidate_config)
- if File.exist?(candidate_config)
+ if Chef::Application.config_file_exists?(candidate_config)
return candidate_config
end
end
@@ -403,12 +402,17 @@ class Chef
end
def configure_chef
- unless config[:config_file]
+ if config[:config_file]
+ if !Chef::Application.config_file_exists?(config[:config_file])
+ ui.error("Specified config file #{config[:config_file]} does not exist#{Chef::Config.config_file_jail ? " or is not under config file jail #{Chef::Config.config_file_jail}" : ""}!")
+ exit 1
+ end
+ else
located_config_file = self.class.locate_config_file
config[:config_file] = located_config_file if located_config_file
end
- # Don't try to load a knife.rb if it doesn't exist.
+ # Don't try to load a knife.rb if it wasn't specified.
if config[:config_file]
Chef::Log.debug("Using configuration from #{config[:config_file]}")
read_config_file(config[:config_file])