diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ef2a5a9..1f9e51b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ appear at the top. ## [Unreleased][] * Your contribution here! -* [#455](https://github.com/capistrano/sshkit/pull/455): Ensure UUID of commands are stable in logging - [@lazyatom](https://github.com/lazyatom) + * [#455](https://github.com/capistrano/sshkit/pull/455): Ensure UUID of commands are stable in logging - [@lazyatom](https://github.com/lazyatom) + * [#453](https://github.com/capistrano/sshkit/pull/453): `as` and `within` now properly escape their user/group/path arguments, and the command nested within an `as` block is now properly escaped before passing to `sh -c`. In the unlikely case that you were manually escaping commands passed to SSHKit as a workaround, you will no longer need to do this. See [#458](https://github.com/capistrano/sshkit/issues/458) for examples of what has been fixed. - [@grosser](https://github.com/grosser) ## [1.18.2][] (2019-02-03) diff --git a/lib/sshkit/backends/abstract.rb b/lib/sshkit/backends/abstract.rb index 79d32235..ba368a65 100644 --- a/lib/sshkit/backends/abstract.rb +++ b/lib/sshkit/backends/abstract.rb @@ -1,3 +1,5 @@ +require 'shellwords' + module SSHKit module Backend @@ -81,12 +83,12 @@ def execute(*args) def within(directory, &_block) (@pwd ||= []).push directory.to_s execute <<-EOTEST, verbosity: Logger::DEBUG - if test ! -d #{File.join(@pwd)} - then echo "Directory does not exist '#{File.join(@pwd)}'" 1>&2 + if test ! -d #{File.join(@pwd).shellescape} + then echo "Directory does not exist '#{File.join(@pwd).shellescape}'" 1>&2 false fi - EOTEST - yield + EOTEST + yield ensure @pwd.pop end @@ -108,8 +110,8 @@ def as(who, &_block) @group = nil end execute <<-EOTEST, verbosity: Logger::DEBUG - if ! sudo -u #{@user} whoami > /dev/null - then echo "You cannot switch to user '#{@user}' using sudo, please check the sudoers file" 1>&2 + if ! sudo -u #{@user.to_s.shellescape} whoami > /dev/null + then echo "You cannot switch to user '#{@user.to_s.shellescape}' using sudo, please check the sudoers file" 1>&2 false fi EOTEST diff --git a/lib/sshkit/command.rb b/lib/sshkit/command.rb index 3c47705d..c0329f18 100644 --- a/lib/sshkit/command.rb +++ b/lib/sshkit/command.rb @@ -1,5 +1,6 @@ require 'digest/sha1' require 'securerandom' +require 'shellwords' # @author Lee Hambley module SSHKit @@ -142,7 +143,7 @@ def should_map? def within(&_block) return yield unless options[:in] - "cd #{options[:in]} && #{yield}" + "cd #{options[:in].shellescape} && #{yield}" end def environment_hash @@ -158,13 +159,15 @@ def environment_string end def with(&_block) - return yield unless environment_hash.any? - "( export #{environment_string} ; #{yield} )" + env_string = environment_string + return yield if env_string.empty? + "( export #{env_string} ; #{yield} )" end def user(&_block) return yield unless options[:user] - "sudo -u #{options[:user]} #{environment_string + " " unless environment_string.empty?}-- sh -c '#{yield}'" + env_string = environment_string + "sudo -u #{options[:user].to_s.shellescape} #{env_string + " " unless env_string.empty?}-- sh -c #{yield.shellescape}" end def in_background(&_block) @@ -179,7 +182,7 @@ def umask(&_block) def group(&_block) return yield unless options[:group] - %Q(sg #{options[:group]} -c "#{yield}") + "sg #{options[:group].to_s.shellescape} -c #{yield.shellescape}" # We could also use the so-called heredoc format perhaps: #"newgrp #{options[:group]} <