module VagrantPlugins module HostDarwin module Cap class SMB @@logger = Log4r::Logger.new("vagrant::host::darwin::smb") # If we have the sharing binary available, smb is installed def self.smb_installed(env) File.exist?("/usr/sbin/sharing") end # Check if the required SMB services are loaded and enabled. If they are # not, then start them up def self.smb_start(env) result = Vagrant::Util::Subprocess.execute("pwpolicy", "gethashtypes") if result.exit_code == 0 && !result.stdout.include?("SMB-NT") @@logger.error("SMB compatible password has not been stored") raise SyncedFolderSMB::Errors::SMBCredentialsMissing end result = Vagrant::Util::Subprocess.execute("launchctl", "list", "com.apple.smb.preferences") if result.exit_code != 0 @@logger.warn("smb preferences service not enabled. enabling and starting...") cmd = ["/bin/launchctl", "load", "-w", "/System/Library/LaunchDaemons/com.apple.smb.preferences.plist"] result = Vagrant::Util::Subprocess.execute("/usr/bin/sudo", *cmd) if result.exit_code != 0 raise SyncedFolderSMB::Errors::SMBStartFailed, command: cmd.join(" "), stderr: result.stderr, stdout: result.stdout end end result = Vagrant::Util::Subprocess.execute("launchctl", "list", "com.apple.smbd") if result.exit_code != 0 @@logger.warn("smbd service not enabled. enabling and starting...") cmd = ["/bin/launchctl", "load", "-w", "/System/Library/LaunchDaemons/com.apple.smbd.plist"] result = Vagrant::Util::Subprocess.execute("/usr/bin/sudo", *cmd) if result.exit_code != 0 raise SyncedFolderSMB::Errors::SMBStartFailed, command: cmd.join(" "), stderr: result.stderr, stdout: result.stdout end Vagrant::Util::Subprocess.execute("/usr/bin/sudo", "/bin/launchctl", "start", "com.apple.smbd") end end # Required options for mounting a share hosted # on macos. def self.smb_mount_options(env) ["sec=ntlmssp", "nounix", "noperm"] end def self.smb_cleanup(env, machine, opts) m_id = machine_id(machine) result = Vagrant::Util::Subprocess.execute("/usr/bin/sudo", "/usr/sbin/sharing", "-l") if result.exit_code != 0 @@logger.warn("failed to locate any shares for cleanup") end shares = result.stdout.split("\n").map do |line| if line.start_with?("name:") share_name = line.sub("name:", "").strip share_name if share_name.start_with?("vgt-#{m_id}") end 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/sudo", "/usr/sbin/sharing", "-r", 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/sudo", "/usr/sbin/sharing", "-a", hostpath, "-S", data[:smb_id], "-s", "001", "-g", "000", "-n", name ] 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