diff --git a/lib/vagrant-sshfs/cap/guest/linux/sshfs_forward_mount.rb b/lib/vagrant-sshfs/cap/guest/linux/sshfs_forward_mount.rb index 3dbc804..d84c71c 100644 --- a/lib/vagrant-sshfs/cap/guest/linux/sshfs_forward_mount.rb +++ b/lib/vagrant-sshfs/cap/guest/linux/sshfs_forward_mount.rb @@ -2,6 +2,7 @@ require "vagrant/util/retryable" require "vagrant/util/platform" require "tempfile" +require Vagrant.source_root.join("plugins/synced_folders/unix_mount_helpers") # This is already done for us in lib/vagrant-sshfs.rb. We needed to # do it there before Process.uid is called the first time by Vagrant @@ -15,6 +16,7 @@ module GuestLinux module Cap class MountSSHFS extend Vagrant::Util::Retryable + extend VagrantPlugins::SyncedFolder::UnixMountHelpers @@logger = Log4r::Logger.new("vagrant::synced_folders::sshfs_mount") def self.list_mounts_command @@ -80,7 +82,25 @@ def self.sshfs_forward_mount_folder(machine, opts) hostpath = File.expand_path(opts[:hostpath], machine.env.root_path) hostpath = Vagrant::Util::Platform.fs_real_path(hostpath).to_s end - + + # Support for user provided mount_options, owner, group + # https://github.com/hashicorp/vagrant/blob/2c3397c46851ef29a3589bf3214a3eee12da8484/website/content/docs/synced-folders/basic_usage.mdx#options + mount_options = opts.fetch(:mount_options, []) + # Determine owner/group info to use + if (opts.has_key?(:owner) and opts[:owner]) or + (opts.has_key?(:group) and opts[:group]) + detected_ids = detect_owner_group_ids( + machine, expanded_guest_path, mount_options, opts) + mount_uid = detected_ids[:uid] + mount_gid = detected_ids[:gid] + mount_options.append("uid=#{mount_uid}") + mount_options.append("gid=#{mount_gid}") + end + # Combine mount_options into sshfs_opts_append (also user provided) + if not mount_options.empty?() + opts[:sshfs_opts_append] = + opts[:sshfs_opts_append].to_s + ' -o ' + mount_options.join(',') + ' ' + end # Add in some sshfs/fuse options that are common to both mount methods opts[:sshfs_opts] = ' -o allow_other ' # allow non-root users to access diff --git a/lib/vagrant-sshfs/cap/host/linux/sshfs_reverse_mount.rb b/lib/vagrant-sshfs/cap/host/linux/sshfs_reverse_mount.rb index 5296409..a632103 100644 --- a/lib/vagrant-sshfs/cap/host/linux/sshfs_reverse_mount.rb +++ b/lib/vagrant-sshfs/cap/host/linux/sshfs_reverse_mount.rb @@ -81,9 +81,50 @@ def self.sshfs_mount(machine, opts) ssh_opts_append = opts[:ssh_opts_append].to_s # provided by user + # Support for user provided mount_options, owner, group + # https://github.com/hashicorp/vagrant/blob/2c3397c46851ef29a3589bf3214a3eee12da8484/website/content/docs/synced-folders/basic_usage.mdx#options + mount_options = opts.fetch(:mount_options, []) + if (opts.has_key?(:owner) and opts[:owner]) or + (opts.has_key?(:group) and opts[:group]) + # Find the `id` command on the system and set the error class + id_command = Vagrant::Util::Which.which('id') + getent_command = Vagrant::Util::Which.which('getent') + error_class = VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSFindUIDGIDFailed + # Identify the uid + cmd = "#{id_command} -u #{opts[:owner]}" + result = Vagrant::Util::Subprocess.execute(*cmd.split()) + if result.exit_code != 0 + raise error_class, command: cmd, stdout: result.stdout, stderr: result.stderr + end + mount_uid = result.stdout.chomp + # Identify the gid. If a group was provided use that otherwise use + # the group detected with the detected user id. + if opts.has_key?(:group) and opts[:group] + cmd = "#{getent_command} group #{opts[:group]}" + result = Vagrant::Util::Subprocess.execute(*cmd.split()) + if result.exit_code != 0 + raise error_class, command: cmd, stdout: result.stdout, stderr: result.stderr + end + mount_gid = result.stdout.split(':').at(2).to_s.chomp + else + cmd = "#{id_command} -g #{mount_uid}" + result = Vagrant::Util::Subprocess.execute(*cmd.split()) + if result.exit_code != 0 + raise error_class, command: cmd, stdout: result.stdout, stderr: result.stderr + end + mount_gid = result.stdout.chomp + end + # Add them to the mount options + mount_options.append("uid=#{mount_uid}") + mount_options.append("gid=#{mount_gid}") + end + # SSHFS executable options sshfs_opts = opts[:sshfs_opts] sshfs_opts_append = opts[:sshfs_opts_append].to_s # provided by user + if not mount_options.empty?() + sshfs_opts_append+= ' -o ' + mount_options.join(',') + ' ' + end username = machine.ssh_info[:username] host = machine.ssh_info[:host] diff --git a/lib/vagrant-sshfs/errors.rb b/lib/vagrant-sshfs/errors.rb index 48d4909..2c17aba 100644 --- a/lib/vagrant-sshfs/errors.rb +++ b/lib/vagrant-sshfs/errors.rb @@ -37,6 +37,10 @@ class SSHFSExeNotAvailable < SSHFSError class SSHFSGetAbsolutePathFailed < SSHFSError error_key(:get_absolute_path_failed) end + + class SSHFSFindUIDGIDFailed < SSHFSError + error_key(:find_uid_gid_failed) + end end end end diff --git a/locales/synced_folder_sshfs.yml b/locales/synced_folder_sshfs.yml index 0f631ba..8b2a471 100644 --- a/locales/synced_folder_sshfs.yml +++ b/locales/synced_folder_sshfs.yml @@ -92,4 +92,18 @@ en: Stderr from the command: + %{stderr} + find_uid_gid_failed: |- + Attempting to find the UID/GID failed. + + The command and output are: + + %{command} + + Stdout from the command: + + %{stdout} + + Stderr from the command: + %{stderr} diff --git a/test/misc/README.txt b/test/misc/README.txt index 6c8c2d6..3c8ff99 100644 --- a/test/misc/README.txt +++ b/test/misc/README.txt @@ -5,12 +5,12 @@ # To test we will first create the directory on the machine where # we will mount the guest /etc/ into the host (the reverse mount). -mkdir /tmp/reverse_mount_etc +mkdir /tmp/reverse_mount_etc_uid_gid/ # Next we will define where our 3rd party host is (the normal mount). # This can be another vagrant box or whatever machine you want. -export THIRD_PARTY_HOST='192.168.121.73' -export THIRD_PARTY_HOST_USER='vagrant' +export THIRD_PARTY_HOST='192.168.121.73' +export THIRD_PARTY_HOST_USER='vagrant' export THIRD_PARTY_HOST_PASS='vagrant' # Open an extra file descriptor to test it is not passed onto child processes @@ -18,27 +18,33 @@ export THIRD_PARTY_HOST_PASS='vagrant' tmpfile=$(mktemp) exec {extra_fd}<> "$tmpfile" -# Next vagrant up - will do 4 mounts +# Next vagrant up - will do 5 mounts # - slave +# - slave with owner/group # - slave with sym link -# - normal -# - reverse +# - normal (from 3rd party host) +# - reverse with owner/group vagrant up # Next run the script to test the mounts: $ bash dotests.sh Testing slave forward mount! - d635332fe7aa4d4fb48e5cb9357bdedf + 1358d4a18a2d4ba7be380b991e899952 +Testing slave forward mount with owner/group! + root:wheel + 1358d4a18a2d4ba7be380b991e899952 Testing slave forward mount with a symlink! - d635332fe7aa4d4fb48e5cb9357bdedf + 1358d4a18a2d4ba7be380b991e899952 Testing normal forward mount! - 6ccc3034df924bd289dd16205bf3d629 -Testing reverse mount! - 508619e7e68e446c84d1fcdf7e0dc577 - -# We are printing out the machine-id under each mount. The first two -should be the same, because they are from the same machine. The last -two should be different. + ef56862ae88f43c0a81962ba6f68a668 +Testing reverse mount with owner/group! + root:wheel + ef4f3b50e2034b3593a9eb8b71350abe + +# We are printing out the machine-id under each mount. The first three +should be the same, because they are from the same machine (the host). +The last two should be different; one from 3rd party machine and one +from the test VM itself (read from the host). # Close our file descriptor. No other process should be using it exec {extra_fd}>&- diff --git a/test/misc/Vagrantfile b/test/misc/Vagrantfile index 09a406a..c734b7c 100644 --- a/test/misc/Vagrantfile +++ b/test/misc/Vagrantfile @@ -4,22 +4,41 @@ Vagrant.configure(2) do |config| # Test a forward slave mount: # mounting /etc/ from the vagrant host into the guest - config.vm.synced_folder "/etc/", "/tmp/forward_slave_mount_etc/", type: "sshfs" + config.vm.synced_folder "/etc/", "/tmp/forward_slave_mount_etc/", + type: "sshfs", + mount_options: ['ro'] + + # Test a forward slave with owner/group info: + # mounting /etc/ from the vagrant host into the guest + config.vm.synced_folder "/etc/", "/tmp/forward_slave_mount_etc_uid_gid/", + type: "sshfs", + mount_options: ['ro', 'default_permissions'], + owner: "root", + group: "wheel" # Test a forward mount to a location that is a symbolic link # https://github.com/dustymabe/vagrant-sshfs/issues/44 - config.vm.synced_folder "/etc/", "/var/run/forward_slave_mount_sym_link_test/", type: "sshfs" + config.vm.synced_folder "/etc/", "/var/run/forward_slave_mount_sym_link_test/", + type: "sshfs", + mount_options: ['ro'] # Test a forward normal mount: # mounting a folder from a 3rd party host into guest - config.vm.synced_folder "/etc/", "/tmp/forward_normal_mount_etc/", type: "sshfs", + config.vm.synced_folder "/etc/", "/tmp/forward_normal_mount_etc/", + type: "sshfs", ssh_host: ENV['THIRD_PARTY_HOST'], ssh_username: ENV['THIRD_PARTY_HOST_USER'], - ssh_password: ENV['THIRD_PARTY_HOST_PASS'] + ssh_password: ENV['THIRD_PARTY_HOST_PASS'], + mount_options: ['ro'] - # Test a reverse mount: + # Test a reverse mount with owner/group # mounting /etc/ from vagrant guest into vagrant host - config.vm.synced_folder "/tmp/reverse_mount_etc/", "/etc", type: "sshfs", reverse: true + config.vm.synced_folder "/tmp/reverse_mount_etc_uid_gid/", "/etc", + type: "sshfs", + reverse: true, + owner: "root", + group: "wheel", + mount_options: ['ro'] host = 'sshfs-tests' box = 'fedora/34-cloud-base' diff --git a/test/misc/dotests.sh b/test/misc/dotests.sh index e80b4c9..68daac7 100644 --- a/test/misc/dotests.sh +++ b/test/misc/dotests.sh @@ -6,6 +6,11 @@ set -eu echo -en "Testing slave forward mount!\n\t" vagrant ssh -- cat /tmp/forward_slave_mount_etc/machine-id +echo -en "Testing slave forward mount with owner/group!\n\t" +vagrant ssh -- stat --printf '%U:%G' /tmp/forward_slave_mount_etc_uid_gid +echo -en "\n\t" +vagrant ssh -- cat /tmp/forward_slave_mount_etc_uid_gid/machine-id + # https://github.com/dustymabe/vagrant-sshfs/issues/44 echo -en "Testing slave forward mount with a symlink!\n\t" vagrant ssh -- cat /run/forward_slave_mount_sym_link_test/machine-id @@ -13,5 +18,7 @@ vagrant ssh -- cat /run/forward_slave_mount_sym_link_test/machine-id echo -en "Testing normal forward mount!\n\t" vagrant ssh -- cat /tmp/forward_normal_mount_etc/machine-id -echo -en "Testing reverse mount!\n\t" -cat /tmp/reverse_mount_etc/machine-id +echo -en "Testing reverse mount with owner/group!\n\t" +stat --printf '%U:%G' /tmp/reverse_mount_etc_uid_gid/ +echo -en "\n\t" +cat /tmp/reverse_mount_etc_uid_gid/machine-id