From ed7139fa1e896d0b84ed32180b72a647bf9f37eb Mon Sep 17 00:00:00 2001
From: Rui Lopes <rgl@ruilopes.com>
Date: Sun, 24 Jun 2018 14:13:52 +0100
Subject: [PATCH] add smb capability to linux hosts

---
 .../linux/cap/configured_ip_addresses.rb      | 17 ++++
 plugins/hosts/linux/cap/smb.rb                | 79 +++++++++++++++++++
 plugins/hosts/linux/plugin.rb                 | 20 +++++
 3 files changed, 116 insertions(+)
 create mode 100644 plugins/hosts/linux/cap/configured_ip_addresses.rb
 create mode 100644 plugins/hosts/linux/cap/smb.rb

diff --git a/plugins/hosts/linux/cap/configured_ip_addresses.rb b/plugins/hosts/linux/cap/configured_ip_addresses.rb
new file mode 100644
index 000000000..f96da7204
--- /dev/null
+++ b/plugins/hosts/linux/cap/configured_ip_addresses.rb
@@ -0,0 +1,17 @@
+require "socket"
+
+module VagrantPlugins
+  module HostLinux
+    module Cap
+      class ConfiguredIPAddresses
+        def self.configured_ip_addresses(env)
+          Socket.getifaddrs.map do |interface|
+            if interface.addr.ipv4? && !interface.addr.ipv4_loopback?
+              interface.addr.ip_address
+            end
+          end.compact
+        end
+      end
+    end
+  end
+end
diff --git a/plugins/hosts/linux/cap/smb.rb b/plugins/hosts/linux/cap/smb.rb
new file mode 100644
index 000000000..10dc1f3f4
--- /dev/null
+++ b/plugins/hosts/linux/cap/smb.rb
@@ -0,0 +1,79 @@
+module VagrantPlugins
+  module HostLinux
+    module Cap
+      class SMB
+        @@logger = Log4r::Logger.new("vagrant::host::linux::smb")
+
+        # If we have the sharing binary available, smb is installed
+        def self.smb_installed(env)
+          File.exist?("/usr/bin/net")
+        end
+
+        def self.smb_cleanup(env, machine, opts)
+          m_id = machine_id(machine)
+          result = Vagrant::Util::Subprocess.execute("/usr/bin/net", "usershare", "list")
+          if result.exit_code != 0
+            @@logger.warn("failed to locate any shares for cleanup")
+          end
+          shares = result.stdout.split("\n").map do |line|
+            line if line.start_with?("vgt-#{m_id}")
+          end.compact
+          @@logger.debug("shares to be removed: #{shares}")
+          shares.each do |share_name|
+            @@logger.info("removing share name=#{share_name}")
+            share_name.strip!
+            result = Vagrant::Util::Subprocess.execute("/usr/bin/net", "usershare", "delete", share_name)
+            if result.exit_code != 0
+              # Removing always returns 0 even if there are currently
+              # guests attached so if we get a non-zero value just
+              # log it as unexpected
+              @@logger.warn("removing share `#{share_name}` returned non-zero")
+            end
+          end
+        end
+
+        def self.smb_prepare(env, machine, folders, opts)
+          folders.each do |id, data|
+            hostpath = data[:hostpath]
+
+            chksum_id = Digest::MD5.hexdigest(id)
+            name = "vgt-#{machine_id(machine)}-#{chksum_id}"
+            data[:smb_id] ||= name
+
+            @@logger.info("creating new share name=#{name} id=#{data[:smb_id]}")
+
+            cmd = [
+              "/usr/bin/net",
+              "usershare",
+              "add",
+              name,
+              hostpath,
+              '', # comment
+              "Everyone:R,#{data[:smb_username] || ENV['USER']}:F" # ACL
+            ]
+
+            r = Vagrant::Util::Subprocess.execute(*cmd)
+
+            if r.exit_code != 0
+              raise VagrantPlugins::SyncedFolderSMB::Errors::DefineShareFailed,
+                host: hostpath.to_s,
+                stderr: r.stderr,
+                stdout: r.stdout
+            end
+          end
+        end
+
+        # Generates a unique identifier for the given machine
+        # based on the name, provider name, and working directory
+        # of the environment.
+        #
+        # @param [Vagrant::Machine] machine
+        # @return [String]
+        def self.machine_id(machine)
+          @@logger.debug("generating machine ID name=#{machine.name} cwd=#{machine.env.cwd}")
+          Digest::MD5.hexdigest("#{machine.name}-#{machine.provider_name}-#{machine.env.cwd}")
+        end
+      end
+    end
+  end
+end
diff --git a/plugins/hosts/linux/plugin.rb b/plugins/hosts/linux/plugin.rb
index a4c6311bf..669be2515 100644
--- a/plugins/hosts/linux/plugin.rb
+++ b/plugins/hosts/linux/plugin.rb
@@ -52,6 +52,26 @@ module VagrantPlugins
         require_relative "cap/ssh"
         Cap::SSH
       end
+
+      host_capability("linux", "smb_installed") do
+        require_relative "cap/smb"
+        Cap::SMB
+      end
+
+      host_capability("linux", "smb_prepare") do
+        require_relative "cap/smb"
+        Cap::SMB
+      end
+
+      host_capability("linux", "smb_cleanup") do
+        require_relative "cap/smb"
+        Cap::SMB
+      end
+
+      host_capability("linux", "configured_ip_addresses") do
+        require_relative "cap/configured_ip_addresses"
+        Cap::ConfiguredIPAddresses
+      end
     end
   end
 end