SparkleShare/Sparkles/SSHFetcher.cs

139 lines
4.9 KiB
C#
Raw Normal View History

2013-10-11 15:13:46 +00:00
// SparkleShare, a collaboration and sharing tool.
2017-07-23 12:47:54 +00:00
// Copyright (C) 2010 Hylke Bons <hi@planetpeanut.uk>
2013-10-11 15:13:46 +00:00
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.IO;
using System.Security.Cryptography;
2016-03-31 08:35:26 +00:00
namespace Sparkles {
2016-03-25 19:34:18 +00:00
2016-03-30 23:36:31 +00:00
public abstract class SSHFetcher : BaseFetcher {
2016-10-25 09:25:34 +00:00
public static string SSHKeyScan = "ssh-keyscan";
2018-03-10 12:26:24 +00:00
protected SSHFetcher (SparkleFetcherInfo info) : base (info)
{
}
public override bool Fetch ()
{
2016-03-25 19:34:18 +00:00
string host_key = FetchHostKey ();
2018-03-10 12:35:17 +00:00
bool host_key_warning = false;
2016-03-25 19:34:18 +00:00
if (string.IsNullOrEmpty (RemoteUrl.Host) || host_key == null) {
2016-03-30 23:36:31 +00:00
Logger.LogInfo ("Auth", "Could not fetch host key");
errors.Add ("error: Could not fetch host key");
2016-03-25 19:34:18 +00:00
return false;
}
2016-03-25 19:34:18 +00:00
if (RequiredFingerprint != null) {
string host_fingerprint = DeriveFingerprint (host_key);
2018-03-10 12:32:33 +00:00
if (host_fingerprint == null || RequiredFingerprint!= host_fingerprint) {
2016-03-30 23:36:31 +00:00
Logger.LogInfo ("Auth", "Fingerprint doesn't match");
errors.Add ("error: Host fingerprint doesn't match");
2018-03-10 12:32:33 +00:00
2016-03-25 19:34:18 +00:00
return false;
}
2018-03-10 12:32:33 +00:00
2016-03-30 23:36:31 +00:00
Logger.LogInfo ("Auth", "Fingerprint matches");
2018-03-10 12:32:33 +00:00
2016-03-25 19:34:18 +00:00
} else {
2016-03-30 23:36:31 +00:00
Logger.LogInfo ("Auth", "Skipping fingerprint check");
2018-03-10 12:32:33 +00:00
host_key_warning = true;
}
2018-03-10 12:32:33 +00:00
AcceptHostKey (host_key, host_key_warning);
return true;
}
string FetchHostKey ()
{
Logger.LogInfo ("Auth", string.Format ("Fetching host key for {0}", RemoteUrl.Host));
2016-10-25 09:25:34 +00:00
var ssh_keyscan = new Command (SSHKeyScan, string.Format ("-t rsa -p 22 {0}", RemoteUrl.Host));
if (RemoteUrl.Port > 0)
ssh_keyscan.StartInfo.Arguments = string.Format ("-t rsa -p {0} {1}", RemoteUrl.Port, RemoteUrl.Host);
string host_key = ssh_keyscan.StartAndReadStandardOutput ();
if (ssh_keyscan.ExitCode == 0 && !string.IsNullOrWhiteSpace (host_key))
return host_key;
return null;
}
2018-03-10 12:26:24 +00:00
string DeriveFingerprint (string public_key)
{
try {
SHA256 sha256 = new SHA256CryptoServiceProvider ();
string key = public_key.Split (" ".ToCharArray ()) [2];
byte [] base64_bytes = Convert.FromBase64String (key);
byte [] sha256_bytes = sha256.ComputeHash (base64_bytes);
string fingerprint = BitConverter.ToString (sha256_bytes);
2018-03-10 12:26:24 +00:00
fingerprint = fingerprint.ToLower ().Replace ("-", ":");
return fingerprint;
} catch (Exception e) {
2018-03-10 12:26:24 +00:00
Logger.LogInfo ("Fetcher", "Failed to create fingerprint: ", e);
return null;
}
}
2018-03-10 12:26:24 +00:00
void AcceptHostKey (string host_key, bool warn)
{
string ssh_config_path = Path.Combine (Configuration.DefaultConfiguration.DirectoryPath, "ssh");
string known_hosts_file_path = Path.Combine (ssh_config_path, "known_hosts");
2018-03-10 12:26:24 +00:00
if (!File.Exists (known_hosts_file_path)) {
if (!Directory.Exists (ssh_config_path))
Directory.CreateDirectory (ssh_config_path);
2018-03-10 12:26:24 +00:00
File.Create (known_hosts_file_path).Close ();
}
2018-03-10 12:26:24 +00:00
string host = RemoteUrl.Host;
string known_hosts = File.ReadAllText (known_hosts_file_path);
string [] known_hosts_lines = File.ReadAllLines (known_hosts_file_path);
2018-03-10 12:26:24 +00:00
foreach (string line in known_hosts_lines) {
if (line.StartsWith (host + " ", StringComparison.InvariantCulture))
return;
}
2018-03-10 12:26:24 +00:00
if (known_hosts.EndsWith ("\n", StringComparison.InvariantCulture))
File.AppendAllText (known_hosts_file_path, host_key + "\n");
else
File.AppendAllText (known_hosts_file_path, "\n" + host_key + "\n");
2018-03-10 12:26:24 +00:00
2016-03-30 23:36:31 +00:00
Logger.LogInfo ("Auth", "Accepted host key for " + host);
2018-03-10 12:26:24 +00:00
if (warn)
warnings.Add ("The following host key has been accepted:\n" + DeriveFingerprint (host_key));
}
}
}