diff --git a/BuildTools/GnupgSigningTool/Program.cs b/BuildTools/GnupgSigningTool/Program.cs index e53422ead..7470001aa 100644 --- a/BuildTools/GnupgSigningTool/Program.cs +++ b/BuildTools/GnupgSigningTool/Program.cs @@ -21,6 +21,7 @@ namespace GnupgSigningTool { var armorOption = useArmor ? "--armor" : ""; + var gpgArgument = string.Format("--pinentry-mode loopback --passphrase-fd 0 --batch --yes {0} -u \"{1}\" --output \"{2}\" --detach-sig \"{3}\"", armorOption, gpgkeyid, @@ -36,6 +37,7 @@ namespace GnupgSigningTool }); proc.StandardInput.WriteLine(gpgkeypassphrase); + proc.WaitForExit(); } @@ -45,18 +47,20 @@ namespace GnupgSigningTool using (var ms = new System.IO.MemoryStream()) using (var fs = System.IO.File.OpenRead(gpgkeyfile)) { - try { enc.Decrypt(fs, ms); - } catch (System.Security.Cryptography.CryptographicException e) { + } + catch (System.Security.Cryptography.CryptographicException e) + { throw new ArgumentException("Failed to decrypt gpg secret credentials file: {0}\n", e.Message); } + ms.Position = 0; using (var sr = new System.IO.StreamReader(ms)) { - var lines = sr.ReadToEnd().Split(new [] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); + var lines = sr.ReadToEnd().Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); gpgkeyid = lines[0]; gpgkeypassphrase = lines[1]; } @@ -64,7 +68,7 @@ namespace GnupgSigningTool } - public static void Main(string [] _args) + public static void Main(string[] _args) { var args = new List(_args); var opts = Duplicati.Library.Utility.CommandLineParser.ExtractOptions(args); @@ -95,7 +99,8 @@ namespace GnupgSigningTool throw new ArgumentException("Could not fetch gpg key id or gpg passphrase."); } - gpgpath = gpgpath ?? "gpg"; + gpgpath = gpgpath ?? Duplicati.Library.Encryption.GPGEncryption.GetGpgExePath(); + SpawnGPG(); } } diff --git a/Duplicati/CommandLine/Program.cs b/Duplicati/CommandLine/Program.cs index 5eef3343e..517cb0402 100644 --- a/Duplicati/CommandLine/Program.cs +++ b/Duplicati/CommandLine/Program.cs @@ -22,8 +22,8 @@ using System.Collections.Generic; using System.Linq; using Duplicati.Library.Localization.Short; using System.IO; -using Duplicati.Library.Common; - +using Duplicati.Library.Logging; + namespace Duplicati.CommandLine { public class Program @@ -48,20 +48,6 @@ namespace Duplicati.CommandLine FROM_COMMANDLINE = true; try { - //If we are on Windows, append the bundled "win-tools" programs to the search path - //We add it last, to allow the user to override with other versions - if (Platform.IsClientWindows) - { - string wintools = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "win-tools"); - Environment.SetEnvironmentVariable("PATH", - Environment.GetEnvironmentVariable("PATH") + - System.IO.Path.PathSeparator.ToString() + - wintools + - System.IO.Path.PathSeparator.ToString() + - System.IO.Path.Combine(wintools, "gpg") //GPG needs to be in a subfolder for wrapping reasons - ); - } - return RunCommandLine(Console.Out, Console.Error, c => { }, args); } finally @@ -74,51 +60,51 @@ namespace Duplicati.CommandLine { get { - var knownCommands = new Dictionary, List, Dictionary, Library.Utility.IFilter, int>>(StringComparer.OrdinalIgnoreCase); - knownCommands["help"] = Commands.Help; - knownCommands["example"] = Commands.Examples; - knownCommands["examples"] = Commands.Examples; - - knownCommands["find"] = Commands.List; - knownCommands["list"] = Commands.List; - - knownCommands["delete"] = Commands.Delete; - knownCommands["backup"] = Commands.Backup; - knownCommands["restore"] = Commands.Restore; - - knownCommands["repair"] = Commands.Repair; - knownCommands["purge"] = Commands.PurgeFiles; - knownCommands["list-broken-files"] = Commands.ListBrokenFiles; - knownCommands["purge-broken-files"] = Commands.PurgeBrokenFiles; - - knownCommands["compact"] = Commands.Compact; - knownCommands["create-report"] = Commands.CreateBugReport; - knownCommands["compare"] = Commands.ListChanges; - knownCommands["test"] = Commands.Test; - knownCommands["verify"] = Commands.Test; - knownCommands["test-filters"] = Commands.TestFilters; - knownCommands["test-filter"] = Commands.TestFilters; - knownCommands["affected"] = Commands.Affected; - knownCommands["vacuum"] = Commands.Vacuum; - - knownCommands["system-info"] = Commands.SystemInfo; - knownCommands["systeminfo"] = Commands.SystemInfo; - - knownCommands["send-mail"] = Commands.SendMail; - + var knownCommands = + new Dictionary, List, + Dictionary, Library.Utility.IFilter, int>>(StringComparer.OrdinalIgnoreCase) + { + ["help"] = Commands.Help, + ["example"] = Commands.Examples, + ["examples"] = Commands.Examples, + ["find"] = Commands.List, + ["list"] = Commands.List, + ["delete"] = Commands.Delete, + ["backup"] = Commands.Backup, + ["restore"] = Commands.Restore, + ["repair"] = Commands.Repair, + ["purge"] = Commands.PurgeFiles, + ["list-broken-files"] = Commands.ListBrokenFiles, + ["purge-broken-files"] = Commands.PurgeBrokenFiles, + ["compact"] = Commands.Compact, + ["create-report"] = Commands.CreateBugReport, + ["compare"] = Commands.ListChanges, + ["test"] = Commands.Test, + ["verify"] = Commands.Test, + ["test-filters"] = Commands.TestFilters, + ["test-filter"] = Commands.TestFilters, + ["affected"] = Commands.Affected, + ["vacuum"] = Commands.Vacuum, + ["system-info"] = Commands.SystemInfo, + ["systeminfo"] = Commands.SystemInfo, + ["send-mail"] = Commands.SendMail + }; + return knownCommands; } } public static IEnumerable SupportedCommands { get { return CommandMap.Keys; } } - private static int ShowChangeLog(TextWriter outwriter) { + private static int ShowChangeLog(TextWriter outwriter) + { var path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "changelog.txt"); outwriter.WriteLine(System.IO.File.ReadAllText(path)); return 0; } - private static void CheckForUpdates(TextWriter outwriter){ + private static void CheckForUpdates(TextWriter outwriter) + { var update = Library.AutoUpdater.UpdaterManager.LastUpdateCheckVersion; if (update == null) update = Library.AutoUpdater.UpdaterManager.CheckForUpdate(); @@ -140,7 +126,8 @@ namespace Duplicati.CommandLine } } - private static int ParseCommandLine(TextWriter outwriter, Action setup, ref bool verboseErrors, string[] args) { + private static int ParseCommandLine(TextWriter outwriter, Action setup, ref bool verboseErrors, string[] args) + { List cargs = new List(args); var tmpparsed = Library.Utility.FilterCollector.ExtractOptions(cargs); @@ -168,7 +155,7 @@ namespace Duplicati.CommandLine } // try and parse all parameter file aliases - foreach (string parameterOption in new []{ "parameters-file", "parameters-file", "parameterfile"} ) + foreach (string parameterOption in new[] { "parameters-file", "parameters-file", "parameterfile" }) { if (options.ContainsKey(parameterOption) && !string.IsNullOrEmpty(options[parameterOption])) { @@ -305,7 +292,8 @@ namespace Duplicati.CommandLine string appendfilter = null; string replacefilter = null; - var tmpparsed = Library.Utility.FilterCollector.ExtractOptions(fargs, (key, value) => { + var tmpparsed = Library.Utility.FilterCollector.ExtractOptions(fargs, (key, value) => + { if (key.Equals("source", StringComparison.OrdinalIgnoreCase)) { newsource.Add(value); @@ -347,27 +335,27 @@ namespace Duplicati.CommandLine filter = newfilter; if (!string.IsNullOrWhiteSpace(prependfilter)) - filter = Library.Utility.FilterExpression.Combine(Library.Utility.FilterExpression.Deserialize(prependfilter.Split(new string[] {System.IO.Path.PathSeparator.ToString()}, StringSplitOptions.RemoveEmptyEntries)), filter); + filter = Library.Utility.FilterExpression.Combine(Library.Utility.FilterExpression.Deserialize(prependfilter.Split(new string[] { System.IO.Path.PathSeparator.ToString() }, StringSplitOptions.RemoveEmptyEntries)), filter); if (!string.IsNullOrWhiteSpace(appendfilter)) - filter = Library.Utility.FilterExpression.Combine(filter, Library.Utility.FilterExpression.Deserialize(appendfilter.Split(new string[] {System.IO.Path.PathSeparator.ToString()}, StringSplitOptions.RemoveEmptyEntries))); + filter = Library.Utility.FilterExpression.Combine(filter, Library.Utility.FilterExpression.Deserialize(appendfilter.Split(new string[] { System.IO.Path.PathSeparator.ToString() }, StringSplitOptions.RemoveEmptyEntries))); if (!string.IsNullOrWhiteSpace(replacefilter)) - filter = Library.Utility.FilterExpression.Deserialize(replacefilter.Split(new string[] {System.IO.Path.PathSeparator.ToString()}, StringSplitOptions.RemoveEmptyEntries)); + filter = Library.Utility.FilterExpression.Deserialize(replacefilter.Split(new string[] { System.IO.Path.PathSeparator.ToString() }, StringSplitOptions.RemoveEmptyEntries)); foreach (KeyValuePair keyvalue in opt) options[keyvalue.Key] = keyvalue.Value; if (!string.IsNullOrEmpty(newtarget)) - { - if (cargs.Count <= 1) - cargs.Add(newtarget); - else - cargs[1] = newtarget; - } + { + if (cargs.Count <= 1) + cargs.Add(newtarget); + else + cargs[1] = newtarget; + } if (cargs.Count >= 1 && cargs[0].Equals("backup", StringComparison.OrdinalIgnoreCase)) - cargs.AddRange(newsource); + cargs.AddRange(newsource); else if (newsource.Count > 0) Library.Logging.Log.WriteVerboseMessage(LOGTAG, "NotUsingBackupSources", Strings.Program.SkippingSourceArgumentsOnNonBackupOperation); diff --git a/Duplicati/Library/Encryption/Duplicati.Library.Encryption.csproj b/Duplicati/Library/Encryption/Duplicati.Library.Encryption.csproj index fe6ebca6c..ff2989050 100644 --- a/Duplicati/Library/Encryption/Duplicati.Library.Encryption.csproj +++ b/Duplicati/Library/Encryption/Duplicati.Library.Encryption.csproj @@ -53,6 +53,10 @@ + + {d63e53e4-a458-4c2f-914d-92f715f58acf} + Duplicati.Library.Common + {c5899f45-b0ff-483c-9d38-24a9fcaab237} Duplicati.Library.Interface diff --git a/Duplicati/Library/Encryption/GPGEncryption.cs b/Duplicati/Library/Encryption/GPGEncryption.cs index b53a98aef..31e074207 100644 --- a/Duplicati/Library/Encryption/GPGEncryption.cs +++ b/Duplicati/Library/Encryption/GPGEncryption.cs @@ -21,6 +21,9 @@ using System; using System.Collections.Generic; using System.IO; using Duplicati.Library.Interface; +using Duplicati.Library.Common; +using Duplicati.Library.Logging; +using Duplicati.Library.Utility; namespace Duplicati.Library.Encryption { @@ -95,8 +98,8 @@ namespace Duplicati.Library.Encryption /// /// The PGP program to use, should be with absolute path /// - private readonly string m_programpath = "gpg"; - + private string m_programpath { get; set; } = GetGpgProgramPath(); + /// /// Commandline switches for encryption /// @@ -272,5 +275,15 @@ namespace Duplicati.Library.Encryption Utility.Utility.CopyStream((Stream)tmp[0], (Stream)tmp[1]); ((Stream)tmp[1]).Close(); } + + /// + /// Determines the path to the GPG program + /// + public static string GetGpgProgramPath() + { + Log.WriteInformationMessage("GetGpgProgramPath", "gpg", Platform.IsClientWindows ? WinTools.GetWindowsGpgExePath() : "gpg"); + // for Windows return the full path, otherwise just return "gpg" + return Platform.IsClientWindows ? WinTools.GetWindowsGpgExePath() : "gpg"; + } } } diff --git a/Duplicati/Library/Utility/Duplicati.Library.Utility.csproj b/Duplicati/Library/Utility/Duplicati.Library.Utility.csproj index 2c0a129b5..04c795270 100644 --- a/Duplicati/Library/Utility/Duplicati.Library.Utility.csproj +++ b/Duplicati/Library/Utility/Duplicati.Library.Utility.csproj @@ -50,12 +50,14 @@ + + @@ -104,6 +106,10 @@ --> + + {d63e53e4-a458-4c2f-914d-92f715f58acf} + Duplicati.Library.Common + {B68F2214-951F-4F78-8488-66E1ED3F50BF} Duplicati.Library.Localization @@ -112,10 +118,6 @@ {C5899F45-B0FF-483C-9D38-24A9FCAAB237} Duplicati.Library.Interface - - {D63E53E4-A458-4C2F-914D-92F715F58ACF} - Duplicati.Library.Common - \ No newline at end of file diff --git a/Duplicati/Library/Utility/RegistryUtility.cs b/Duplicati/Library/Utility/RegistryUtility.cs new file mode 100644 index 000000000..d10a77b2e --- /dev/null +++ b/Duplicati/Library/Utility/RegistryUtility.cs @@ -0,0 +1,50 @@ +#region Disclaimer / License +// Copyright (C) 2019, The Duplicati Team +// http://www.duplicati.com, info@duplicati.com +// +// This library 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 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion +using Microsoft.Win32; + +namespace Duplicati.Library.Utility +{ + public static class RegistryUtility + { + public static string GetDataByValueName(string parentKeyName, string name) + { + try + { + // check currentUser first, if null, then check LocalMachine + // if a registry item does not exist a null is returned + var cuParentKey = Registry.CurrentUser.OpenSubKey(parentKeyName, RegistryKeyPermissionCheck.ReadSubTree); + if (cuParentKey?.GetValue(name) != null) + { + return cuParentKey.GetValue(name).ToString(); + } + + var lmParentKey = Registry.LocalMachine.OpenSubKey(parentKeyName, RegistryKeyPermissionCheck.ReadSubTree); + return lmParentKey.GetValue(name).ToString(); + } + catch + { + // NOOP + } + + return null; + } + + } +} diff --git a/Duplicati/Library/Utility/WinTools.cs b/Duplicati/Library/Utility/WinTools.cs new file mode 100644 index 000000000..02c64fd2a --- /dev/null +++ b/Duplicati/Library/Utility/WinTools.cs @@ -0,0 +1,57 @@ +#region Disclaimer / License +// Copyright (C) 2019, The Duplicati Team +// http://www.duplicati.com, info@duplicati.com +// +// This library 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 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion +using Duplicati.Library.Common; + +namespace Duplicati.Library.Utility +{ + public static class WinTools + { + public static string GetWindowsGpgExePath() + { + if (!Platform.IsClientWindows) + { + return null; + } + + try + { + // return gpg4win if it exists + var location32 = Library.Utility.RegistryUtility.GetDataByValueName(@"SOFTWARE\WOW6432Node\GnuPG", "Install Directory"); + var location64 = Library.Utility.RegistryUtility.GetDataByValueName(@"SOFTWARE\GnuPG", "Install Directory"); + var gpg4winLocation = string.IsNullOrEmpty(location64) ? location32 : location64; + + if (!string.IsNullOrEmpty(gpg4winLocation)) + { + return System.IO.Path.Combine(gpg4winLocation, "bin", "gpg.exe"); + } + } + catch + { + // NOOP + } + + // otherwise return our included win-tools + var wintoolsPath = System.IO.Path.Combine( + System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), + "win-tools", "gpg.exe"); + return string.IsNullOrEmpty(wintoolsPath) ? null : wintoolsPath; + } + } +} diff --git a/Duplicati/Tools/Duplicati.Tools.csproj b/Duplicati/Tools/Duplicati.Tools.csproj index 3506a2ff4..1873dc978 100644 --- a/Duplicati/Tools/Duplicati.Tools.csproj +++ b/Duplicati/Tools/Duplicati.Tools.csproj @@ -44,41 +44,36 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest - - win-tools\gpg.exe - PreserveNewest - - - win-tools\gpgconf.exe - PreserveNewest - - - win-tools\libadns-1.dll - PreserveNewest - - - win-tools\libassuan-0.dll - PreserveNewest - - - win-tools\libgcrypt-20.dll - PreserveNewest - - - win-tools\libgpg-error-0.dll - PreserveNewest - - - win-tools\libiconv-2.dll - PreserveNewest - - - win-tools\zlib1.dll - PreserveNewest - utility-scripts\mozroots.exe PreserveNewest @@ -87,6 +82,9 @@ utility-scripts\TlsTest.exe PreserveNewest + + PreserveNewest + diff --git a/Duplicati/Tools/win-tools/gpg.exe b/Duplicati/Tools/win-tools/gpg.exe new file mode 100644 index 000000000..24cfcc33f Binary files /dev/null and b/Duplicati/Tools/win-tools/gpg.exe differ diff --git a/Duplicati/Tools/win-tools/gpgconf.exe b/Duplicati/Tools/win-tools/gpgconf.exe new file mode 100644 index 000000000..741fc0751 Binary files /dev/null and b/Duplicati/Tools/win-tools/gpgconf.exe differ diff --git a/Duplicati/Tools/win-tools/libassuan-0.dll b/Duplicati/Tools/win-tools/libassuan-0.dll new file mode 100644 index 000000000..a1a796e24 Binary files /dev/null and b/Duplicati/Tools/win-tools/libassuan-0.dll differ diff --git a/Duplicati/Tools/win-tools/libgcrypt-20.dll b/Duplicati/Tools/win-tools/libgcrypt-20.dll new file mode 100644 index 000000000..d90ebefcd Binary files /dev/null and b/Duplicati/Tools/win-tools/libgcrypt-20.dll differ diff --git a/Duplicati/Tools/win-tools/libgpg-error-0.dll b/Duplicati/Tools/win-tools/libgpg-error-0.dll new file mode 100644 index 000000000..2771b1725 Binary files /dev/null and b/Duplicati/Tools/win-tools/libgpg-error-0.dll differ diff --git a/Duplicati/Tools/win-tools/libgpgme-11.dll b/Duplicati/Tools/win-tools/libgpgme-11.dll new file mode 100644 index 000000000..3a82f8ef8 Binary files /dev/null and b/Duplicati/Tools/win-tools/libgpgme-11.dll differ diff --git a/Duplicati/Tools/win-tools/libksba-8.dll b/Duplicati/Tools/win-tools/libksba-8.dll new file mode 100644 index 000000000..f9edd94e7 Binary files /dev/null and b/Duplicati/Tools/win-tools/libksba-8.dll differ diff --git a/Duplicati/Tools/win-tools/libnpth-0.dll b/Duplicati/Tools/win-tools/libnpth-0.dll new file mode 100644 index 000000000..150830891 Binary files /dev/null and b/Duplicati/Tools/win-tools/libnpth-0.dll differ diff --git a/Duplicati/Tools/win-tools/libsqlite3-0.dll b/Duplicati/Tools/win-tools/libsqlite3-0.dll new file mode 100644 index 000000000..fc3f30888 Binary files /dev/null and b/Duplicati/Tools/win-tools/libsqlite3-0.dll differ diff --git a/Duplicati/Tools/win-tools/zlib1.dll b/Duplicati/Tools/win-tools/zlib1.dll new file mode 100644 index 000000000..ae0babbd8 Binary files /dev/null and b/Duplicati/Tools/win-tools/zlib1.dll differ diff --git a/thirdparty/gpg/gpg.exe b/thirdparty/gpg/gpg.exe index 5c3a88dec..24cfcc33f 100644 Binary files a/thirdparty/gpg/gpg.exe and b/thirdparty/gpg/gpg.exe differ diff --git a/thirdparty/gpg/gpgconf.exe b/thirdparty/gpg/gpgconf.exe index d3364b2f0..741fc0751 100644 Binary files a/thirdparty/gpg/gpgconf.exe and b/thirdparty/gpg/gpgconf.exe differ diff --git a/thirdparty/gpg/libadns-1.dll b/thirdparty/gpg/libadns-1.dll deleted file mode 100644 index e16f4d41f..000000000 Binary files a/thirdparty/gpg/libadns-1.dll and /dev/null differ diff --git a/thirdparty/gpg/libassuan-0.dll b/thirdparty/gpg/libassuan-0.dll index f745958c0..a1a796e24 100644 Binary files a/thirdparty/gpg/libassuan-0.dll and b/thirdparty/gpg/libassuan-0.dll differ diff --git a/thirdparty/gpg/libgcrypt-20.dll b/thirdparty/gpg/libgcrypt-20.dll index 93c2860c5..d90ebefcd 100644 Binary files a/thirdparty/gpg/libgcrypt-20.dll and b/thirdparty/gpg/libgcrypt-20.dll differ diff --git a/thirdparty/gpg/libgpg-error-0.dll b/thirdparty/gpg/libgpg-error-0.dll index ffdd5f0a7..2771b1725 100644 Binary files a/thirdparty/gpg/libgpg-error-0.dll and b/thirdparty/gpg/libgpg-error-0.dll differ diff --git a/thirdparty/gpg/libgpgme-11.dll b/thirdparty/gpg/libgpgme-11.dll new file mode 100644 index 000000000..3a82f8ef8 Binary files /dev/null and b/thirdparty/gpg/libgpgme-11.dll differ diff --git a/thirdparty/gpg/libiconv-2.dll b/thirdparty/gpg/libiconv-2.dll deleted file mode 100644 index 73e33d190..000000000 Binary files a/thirdparty/gpg/libiconv-2.dll and /dev/null differ diff --git a/thirdparty/gpg/libksba-8.dll b/thirdparty/gpg/libksba-8.dll new file mode 100644 index 000000000..f9edd94e7 Binary files /dev/null and b/thirdparty/gpg/libksba-8.dll differ diff --git a/thirdparty/gpg/libnpth-0.dll b/thirdparty/gpg/libnpth-0.dll new file mode 100644 index 000000000..150830891 Binary files /dev/null and b/thirdparty/gpg/libnpth-0.dll differ diff --git a/thirdparty/gpg/zlib1.dll b/thirdparty/gpg/zlib1.dll index 94dbcf05f..ae0babbd8 100644 Binary files a/thirdparty/gpg/zlib1.dll and b/thirdparty/gpg/zlib1.dll differ