123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- using System;
- using System.Collections.Generic;
- using System.Runtime.InteropServices;
- using System.Text.RegularExpressions;
- using System.Globalization;
- using System.Security;
- namespace WinSCP
- {
- [Guid("F25C49A5-74A6-4E8F-AEB4-5B4E0DDF0EF9")]
- [ComVisible(true)]
- public enum Protocol
- {
- Sftp = 0,
- Scp = 1,
- Ftp = 2,
- Webdav = 3,
- S3 = 4,
- }
- [Guid("D924FAB9-FCE7-47B8-9F23-5717698384D3")]
- [ComVisible(true)]
- public enum FtpMode
- {
- Passive = 0,
- Active = 1,
- }
- [Guid("F2FC81EB-4761-4A4E-A3EC-4AFDD474C18C")]
- [ComVisible(true)]
- public enum FtpSecure
- {
- None = 0,
- Implicit = 1,
- Explicit = 3,
- }
- [Guid("2D4EF368-EE80-4C15-AE77-D12AEAF4B00A")]
- [ClassInterface(Constants.ClassInterface)]
- [ComVisible(true)]
- public sealed class SessionOptions
- {
- public SessionOptions()
- {
- Timeout = new TimeSpan(0, 0, 15);
- RawSettings = new Dictionary<string,string>();
- }
- public Protocol Protocol { get { return _protocol; } set { SetProtocol(value); } }
- public string HostName { get; set; }
- public int PortNumber { get { return _portNumber; } set { SetPortNumber(value); } }
- public string UserName { get; set; }
- public string Password { get { return GetPassword(_securePassword); } set { SetPassword(ref _securePassword, value); } }
- public SecureString SecurePassword { get { return _securePassword; } set { _securePassword = value; } }
- public string NewPassword { get { return GetPassword(_secureNewPassword); } set { SetPassword(ref _secureNewPassword, value); } }
- public SecureString SecureNewPassword { get { return _secureNewPassword; } set { _secureNewPassword = value; } }
- public TimeSpan Timeout { get { return _timeout; } set { SetTimeout(value); } }
- public int TimeoutInMilliseconds { get { return Tools.TimeSpanToMilliseconds(Timeout); } set { Timeout = Tools.MillisecondsToTimeSpan(value); } }
- public string PrivateKeyPassphrase { get { return GetPassword(_securePrivateKeyPassphrase); } set { SetPassword(ref _securePrivateKeyPassphrase, value); } }
- public SecureString SecurePrivateKeyPassphrase { get { return _securePrivateKeyPassphrase; } set { _securePrivateKeyPassphrase = value; } }
- // SSH
- public string SshHostKeyFingerprint { get { return _sshHostKeyFingerprint; } set { SetSshHostKeyFingerprint(value); } }
- public bool GiveUpSecurityAndAcceptAnySshHostKey { get; set; }
- public string SshPrivateKeyPath { get; set; }
- [Obsolete("Use PrivateKeyPassphrase")]
- public string SshPrivateKeyPassphrase { get { return PrivateKeyPassphrase; } set { PrivateKeyPassphrase = value; } }
- // FTP
- public FtpMode FtpMode { get; set; }
- public FtpSecure FtpSecure { get; set; }
- // WebDAV
- public bool WebdavSecure { get; set; }
- public string WebdavRoot { get { return _webdavRoot; } set { SetWebdavRoot(value); } }
- // TLS
- public string TlsHostCertificateFingerprint { get { return _tlsHostCertificateFingerprint; } set { SetHostTlsCertificateFingerprint(value); } }
- public bool GiveUpSecurityAndAcceptAnyTlsHostCertificate { get; set; }
- public string TlsClientCertificatePath { get; set; }
- public void AddRawSettings(string setting, string value)
- {
- RawSettings.Add(setting, value);
- }
- public void ParseUrl(string url)
- {
- if (url == null)
- {
- throw new ArgumentNullException("url");
- }
- url = url.Trim();
- const string protocolSeparator = "://";
- int index = url.IndexOf(protocolSeparator, StringComparison.OrdinalIgnoreCase);
- if (index < 0)
- {
- throw new ArgumentException("Protocol not specified", "url");
- }
- string protocol = url.Substring(0, index).Trim();
- if (!ParseProtocol(protocol))
- {
- throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Unknown protocol {0}", protocol), "url");
- }
- url = url.Substring(index + protocolSeparator.Length).Trim();
- index = url.IndexOf('/');
- WebdavRoot = null;
- if (index >= 0)
- {
- string path = url.Substring(index).Trim();
- url = url.Substring(0, index).Trim();
- string parameters = path;
- path = CutToChar(ref parameters, ';');
- if (!string.IsNullOrEmpty(path) && (path != "/"))
- {
- if (Protocol != Protocol.Webdav)
- {
- throw new ArgumentException("Root folder can be specified for WebDAV protocol only", "url");
- }
- WebdavRoot = path;
- }
- // forward compatibility
- if (!string.IsNullOrEmpty(parameters))
- {
- throw new ArgumentException("No session parameters are supported", "url");
- }
- }
- index = url.LastIndexOf('@');
- string hostInfo;
- string userInfo = null;
- if (index >= 0)
- {
- userInfo = url.Substring(0, index).Trim();
- hostInfo = url.Substring(index + 1).Trim();
- }
- else
- {
- hostInfo = url;
- }
- PortNumber = 0;
- string portNumber = null;
- if ((hostInfo.Length >= 2) && (hostInfo[0] == '[') && ((index = hostInfo.IndexOf(']')) > 0))
- {
- HostName = hostInfo.Substring(1, index - 1).Trim();
- hostInfo = hostInfo.Substring(index + 1).Trim();
- if (hostInfo.Length > 0)
- {
- if (hostInfo[0] != ':')
- {
- throw new ArgumentException("Unexpected syntax after ]", "url");
- }
- else
- {
- portNumber = hostInfo.Substring(1);
- }
- }
- }
- else
- {
- HostName = UriUnescape(CutToChar(ref hostInfo, ':'));
- portNumber = hostInfo;
- }
- if (string.IsNullOrEmpty(HostName))
- {
- throw new ArgumentException("No host name", "url");
- }
- if (string.IsNullOrEmpty(portNumber))
- {
- PortNumber = 0;
- }
- else
- {
- portNumber = UriUnescape(portNumber);
- if (!int.TryParse(portNumber, 0, CultureInfo.InvariantCulture, out int number))
- {
- throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "{0} is not a valid port number", portNumber), "url");
- }
- else
- {
- PortNumber = number;
- }
- }
- UserName = null;
- Password = null;
- SshHostKeyFingerprint = null;
- GiveUpSecurityAndAcceptAnySshHostKey = false;
- TlsHostCertificateFingerprint = null;
- GiveUpSecurityAndAcceptAnyTlsHostCertificate = false;
- if (!string.IsNullOrEmpty(userInfo))
- {
- string parameters = userInfo;
- userInfo = CutToChar(ref parameters, ';');
- UserName = EmptyToNull(UriUnescape(CutToChar(ref userInfo, ':')));
- Password = EmptyToNull(UriUnescape(userInfo));
- while (!string.IsNullOrEmpty(parameters))
- {
- string parameter = CutToChar(ref parameters, ';');
- string parameterName = CutToChar(ref parameter, '=');
- if (parameterName.Equals("fingerprint", StringComparison.OrdinalIgnoreCase))
- {
- SshHostKeyFingerprint = parameter;
- }
- else
- {
- throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Unsupported connection parameter {0}", parameterName), "url");
- }
- }
- }
- }
- private bool ParseProtocol(string protocol)
- {
- bool result = true;
- FtpSecure = FtpSecure.None;
- if (protocol.Equals("sftp", StringComparison.OrdinalIgnoreCase))
- {
- Protocol = Protocol.Sftp;
- }
- else if (protocol.Equals("scp", StringComparison.OrdinalIgnoreCase))
- {
- Protocol = Protocol.Scp;
- }
- else if (protocol.Equals("ftp", StringComparison.OrdinalIgnoreCase))
- {
- Protocol = Protocol.Ftp;
- }
- else if (protocol.Equals("ftps", StringComparison.OrdinalIgnoreCase))
- {
- Protocol = Protocol.Ftp;
- FtpSecure = FtpSecure.Implicit;
- }
- else if (protocol.Equals("ftpes", StringComparison.OrdinalIgnoreCase))
- {
- Protocol = Protocol.Ftp;
- FtpSecure = FtpSecure.Explicit;
- }
- else if (protocol.Equals("dav", StringComparison.OrdinalIgnoreCase) ||
- protocol.Equals("http", StringComparison.OrdinalIgnoreCase))
- {
- Protocol = Protocol.Webdav;
- }
- else if (protocol.Equals("davs", StringComparison.OrdinalIgnoreCase) ||
- protocol.Equals("https", StringComparison.OrdinalIgnoreCase))
- {
- Protocol = Protocol.Webdav;
- WebdavSecure = true;
- }
- else if (protocol.Equals("s3", StringComparison.OrdinalIgnoreCase))
- {
- Protocol = Protocol.S3;
- }
- else
- {
- result = false;
- }
- return result;
- }
- private static string EmptyToNull(string s)
- {
- if (string.IsNullOrEmpty(s))
- {
- return null;
- }
- else
- {
- return s;
- }
- }
- private static string UriUnescape(string s)
- {
- return Uri.UnescapeDataString(s);
- }
- private static string CutToChar(ref string s, char c)
- {
- int index = s.IndexOf(c);
- string result;
- if (index >= 0)
- {
- result = s.Substring(0, index).Trim();
- s = s.Substring(index + 1).Trim();
- }
- else
- {
- result = s;
- s = string.Empty;
- }
- return result;
- }
- internal Dictionary<string, string> RawSettings { get; private set; }
- internal bool IsSsh { get { return (Protocol == Protocol.Sftp) || (Protocol == Protocol.Scp); } }
- internal bool IsTls { get { return GetIsTls(); } }
- private bool GetIsTls()
- {
- return
- ((Protocol == Protocol.Ftp) && (FtpSecure != FtpSecure.None)) ||
- ((Protocol == Protocol.Webdav) && WebdavSecure) ||
- (Protocol == Protocol.S3);
- }
- private void SetSshHostKeyFingerprint(string s)
- {
- if (s != null)
- {
- Match match = _sshHostKeyRegex.Match(s);
- if (!match.Success || (match.Length != s.Length))
- {
- throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "SSH host key fingerprint \"{0}\" does not match pattern /{1}/", s, _sshHostKeyRegex));
- }
- }
- _sshHostKeyFingerprint = s;
- }
- private void SetHostTlsCertificateFingerprint(string s)
- {
- if (s != null)
- {
- Match match = _tlsCertificateRegex.Match(s);
- if (!match.Success || (match.Length != s.Length))
- {
- throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "TLS host certificate fingerprint \"{0}\" does not match pattern /{1}/", s, _tlsCertificateRegex));
- }
- }
- _tlsHostCertificateFingerprint = s;
- }
- private void SetTimeout(TimeSpan value)
- {
- if (value <= TimeSpan.Zero)
- {
- throw new ArgumentException("Timeout has to be positive non-zero value");
- }
- _timeout = value;
- }
- private void SetPortNumber(int value)
- {
- if (value < 0)
- {
- throw new ArgumentException("Port number cannot be negative");
- }
- _portNumber = value;
- }
- private void SetProtocol(Protocol value)
- {
- _protocol = value;
- if ((_protocol == Protocol.S3) && string.IsNullOrEmpty(HostName))
- {
- HostName = "s3.amazonaws.com";
- }
- }
- private void SetWebdavRoot(string value)
- {
- if (!string.IsNullOrEmpty(value) && (value[0] != '/'))
- {
- throw new ArgumentException("WebDAV root path has to start with slash");
- }
- _webdavRoot = value;
- }
- private static void SetPassword(ref SecureString securePassword, string value)
- {
- if (value == null)
- {
- securePassword = null;
- }
- else
- {
- securePassword = new SecureString();
- foreach (char c in value)
- {
- securePassword.AppendChar(c);
- }
- }
- }
- private static string GetPassword(SecureString securePassword)
- {
- if (securePassword == null)
- {
- return null;
- }
- else
- {
- IntPtr ptr = IntPtr.Zero;
- try
- {
- ptr = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
- return Marshal.PtrToStringUni(ptr);
- }
- finally
- {
- Marshal.ZeroFreeGlobalAllocUnicode(ptr);
- }
- }
- }
- private SecureString _securePassword;
- private SecureString _secureNewPassword;
- private SecureString _securePrivateKeyPassphrase;
- private string _sshHostKeyFingerprint;
- private string _tlsHostCertificateFingerprint;
- private TimeSpan _timeout;
- private int _portNumber;
- private string _webdavRoot;
- private Protocol _protocol;
- private const string _listPattern = @"{0}(;{0})*";
- private const string _sshHostKeyPattern = @"((ssh-rsa|ssh-dss|ssh-ed25519|ecdsa-sha2-nistp(256|384|521))( |-))?(\d+ )?([0-9a-f]{2}(:|-)){15}[0-9a-f]{2}";
- private static readonly Regex _sshHostKeyRegex =
- new Regex(string.Format(CultureInfo.InvariantCulture, _listPattern, _sshHostKeyPattern));
- private const string _tlsCertificatePattern = @"([0-9a-f]{2}:){19}[0-9a-f]{2}";
- private static readonly Regex _tlsCertificateRegex =
- new Regex(string.Format(CultureInfo.InvariantCulture, _listPattern, _tlsCertificatePattern));
- }
- }
|