123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- // OpenSSH Handler
- //
- // Douglas Thrift
- //
- // OpensshHandler.cs
- /* Copyright 2014 Douglas Thrift
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IO;
- using System.Linq;
- using System.Text;
- using System.Text.RegularExpressions;
- using Microsoft.Win32;
- public class OpensshHandler : AbstractHandler, Handler
- {
- private Regex regex = new Regex(@"^(?:/|--?)openssh(?:[:=](?<openssh_path>.*))?$", RegexOptions.IgnoreCase);
- private Regex cygwinRegex = new Regex(@"^(?:/|--?)cygwin(?:[:=](?<cygwin_path>.*))?$", RegexOptions.IgnoreCase);
- private Regex minttyRegex = new Regex(@"^(?:/|--?)mintty(?:[:=](?<mintty_path>.*))?$", RegexOptions.IgnoreCase);
- private Regex bashRegex = new Regex(@"^(?:/|--?)bash(?:[:=](?<bash_path>.*))?$", RegexOptions.IgnoreCase);
- private AutoYesNoOption cygwin = AutoYesNoOption.Auto;
- private AutoYesNoOption mintty = AutoYesNoOption.Auto;
- private bool bash = false;
- private string path = null;
- string cygwinPath = null;
- string minttyPath = null;
- string bashPath = null;
- public override IEnumerable<Setting> Settings
- {
- get
- {
- return new Setting[]
- {
- new Setting("/openssh", "/openssh[:<openssh-path>]", "OpenSSH", "Use OpenSSH to connect", SettingType.OptionalExecutable, true),
- new Setting("/cygwin", "/cygwin[:(yes|no|<cygwin-path>)]", "Cygwin", "Use Cygwin for OpenSSH (by default, Cygwin will be used for OpenSSH if detected)", SettingType.OptionalYesNoDirectory),
- new Setting("/mintty", "/mintty[:(yes|no|<mintty-path>)]", "MinTTY", "Use MinTTY for OpenSSH (by default, MinTTY will be used for OpenSSH if detected)", SettingType.OptionalYesNoExecutable),
- new Setting("/bash", "/bash[:(yes|no|<bash-path>)]", "Bash", "Use Bash login shell for use with ssh-agent", SettingType.OptionalYesNoExecutable),
- };
- }
- }
- public MatchOption DoMatch(string arg)
- {
- Match match;
- if ((match = regex.Match(arg)).Success)
- return SetValue(match, "openssh_path", ref path);
- else if ((match = cygwinRegex.Match(arg)).Success)
- return SetYesNoValue(match, "cygwin_path", out cygwin, ref cygwinPath);
- else if ((match = minttyRegex.Match(arg)).Success)
- return SetYesNoValue(match, "mintty_path", out mintty, ref minttyPath);
- else if ((match = bashRegex.Match(arg)).Success)
- return SetBooleanValue(match, "bash_path", out bash, ref bashPath);
- else
- return MatchOption.None;
- }
- public bool Find()
- {
- if (path != null)
- goto Found;
- switch (cygwin)
- {
- case AutoYesNoOption.Auto:
- case AutoYesNoOption.Yes:
- if (FindCygwin())
- goto Found;
- break;
- }
- if ((path = FindInPath("ssh.exe")) != null)
- {
- Debug.WriteLine("Found OpenSSH in path: {0}", path, null);
- goto Found;
- }
- return false;
- Found:
- path = path.Trim();
- switch (mintty)
- {
- case AutoYesNoOption.Auto:
- case AutoYesNoOption.Yes:
- FindMintty();
- break;
- }
- if (bash)
- FindBash();
- return true;
- }
- public void Execute(Uri uri, string user, string password)
- {
- if (!Find())
- throw new Exception("Could not find OpenSSH executable.");
- if (cygwinPath != null && bash)
- {
- ProcessStartInfo info = new ProcessStartInfo(Path.Combine(cygwinPath, "bin", "cygpath.exe"), CygwinQuote(path));
- info.CreateNoWindow = true;
- info.RedirectStandardOutput = true;
- info.RedirectStandardError = true;
- info.UseShellExecute = false;
- Process process = Process.Start(info);
- string error = process.StandardError.ReadToEnd().Trim();
- path = process.StandardOutput.ReadToEnd().Trim();
- process.WaitForExit();
- if (process.ExitCode != 0)
- throw new Exception(error);
- }
- var command = new List<string>(new string[] { path });
- if (password != null)
- Debug.WriteLine("Warning: OpenSSH does not support passing a password.");
- if (uri.Port != -1)
- AddArguments(command, "-p", uri.Port);
- AddArguments(command, user != null ? string.Format("{0}@{1}", user, uri.Host) : uri.Host);
- if (bash)
- {
- command = new List<string>(new string[] { bashPath, "-lc", CygwinCommand(command) });
- }
- if (minttyPath != null)
- {
- var minttyCommand = new List<string>(new string[] { minttyPath });
-
- if (cygwinPath != null)
- {
- string icon = Path.Combine(cygwinPath, "Cygwin-Terminal.ico");
- if (File.Exists(icon))
- AddArguments(minttyCommand, "-i", icon);
- }
- AddArguments(minttyCommand, "-e");
- command.InsertRange(0, minttyCommand);
- }
- string arguments = CygwinCommand(command.Skip(1));
- Debug.WriteLine("Running OpenSSH command: {0} {1}", command.First(), arguments);
- Process.Start(command.First(), arguments);
- }
- private bool FindCygwin()
- {
- if (cygwinPath != null)
- goto Found;
- foreach (var hive in new RegistryHive[] { RegistryHive.CurrentUser, RegistryHive.LocalMachine })
- {
- var views = new List<RegistryView>(new RegistryView[] { RegistryView.Registry32 });
- if (Environment.Is64BitOperatingSystem)
- views.Insert(0, RegistryView.Registry64);
- foreach (RegistryView view in views)
- using (RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, view), key = baseKey.OpenSubKey(@"SOFTWARE\Cygwin\setup"))
- if (key != null)
- {
- cygwinPath = (string)key.GetValue("rootdir");
- if (cygwinPath == null)
- continue;
- if (Directory.Exists(cygwinPath))
- {
- Debug.WriteLine("Found Cygwin in registry: {0}", cygwinPath, null);
- goto Found;
- }
- else
- cygwinPath = null;
- }
- }
- if (cygwin == AutoYesNoOption.Yes)
- throw new Exception("Could not find Cygwin in registry.");
- return false;
- Found:
- cygwinPath = cygwinPath.Trim();
- path = Path.Combine(cygwinPath, "bin", "ssh.exe");
- if (File.Exists(path))
- {
- Debug.WriteLine("Found OpenSSH in Cygwin directory: {0}", path, null);
- return true;
- }
- else if (cygwin == AutoYesNoOption.Yes)
- throw new Exception("Could not find OpenSSH in Cygwin directory.");
- else
- {
- path = null;
- return false;
- }
- }
- private void FindMintty()
- {
- if (minttyPath != null)
- goto Found;
- if (cygwinPath != null)
- {
- minttyPath = Path.Combine(cygwinPath, "bin", "mintty.exe");
- if (File.Exists(minttyPath))
- {
- Debug.WriteLine("Found MinTTY in Cygwin directory: {0}", minttyPath, null);
- goto Found;
- }
- else
- minttyPath = null;
- }
- if ((minttyPath = FindInPath("mintty.exe")) != null)
- {
- Debug.WriteLine("Found MinTTY in path: {0}", minttyPath, null);
- goto Found;
- }
- if (mintty == AutoYesNoOption.Yes)
- throw new Exception("Could not find MinTTY executable.");
- return;
- Found:
- minttyPath = minttyPath.Trim();
- }
- private void FindBash()
- {
- if (bashPath != null)
- goto Found;
- if (cygwinPath != null)
- {
- bashPath = Path.Combine(cygwinPath, "bin", "bash.exe");
- if (File.Exists(bashPath))
- {
- Debug.WriteLine("Found Bash in Cygwin directory: {0}", bashPath, null);
- goto Found;
- }
- else
- bashPath = null;
- }
- if ((bashPath = FindInPath("bash.exe")) != null)
- {
- Debug.WriteLine("Found Bash in path: {0}", bashPath, null);
- goto Found;
- }
- throw new Exception("Could not find Bash executable.");
- Found:
- bashPath = bashPath.Trim();
- }
- private string CygwinQuote(string value)
- {
- return string.Format("'{0}'", value.Replace("\"", "\\\"").Replace('\'', '"'));
- }
- private string CygwinAutoQuote(string value)
- {
- if (Regex.IsMatch(value, "[ '\"]"))
- return CygwinQuote(value);
- else
- return value;
- }
- private string CygwinCommand(IEnumerable<string> command)
- {
- return string.Join(" ", command.Select(item => CygwinAutoQuote(item)));
- }
- }
|