1 /*
2   KeePass Password Safe - The Open-Source Password Manager
3   Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
4 
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19 
20 using System;
21 using System.Diagnostics;
22 using System.IO;
23 using System.Runtime.InteropServices;
24 using System.Text;
25 
26 using KeePassLib.Utility;
27 
28 namespace KeePassLib.Native
29 {
30 	internal static partial class NativeMethods
31 	{
32 		internal const int MAX_PATH = 260;
33 
34 		internal const long INVALID_HANDLE_VALUE = -1;
35 
36 		internal const uint MOVEFILE_REPLACE_EXISTING = 0x00000001;
37 		internal const uint MOVEFILE_COPY_ALLOWED = 0x00000002;
38 
39 		internal const uint FILE_SUPPORTS_TRANSACTIONS = 0x00200000;
40 		internal const int MAX_TRANSACTION_DESCRIPTION_LENGTH = 64;
41 
42 		internal static readonly Guid FOLDERID_SkyDrive = new Guid(
43 			"A52BBA46-E9E1-435F-B3D9-28DAA648C0F6");
44 
45 		// internal const uint TF_SFT_SHOWNORMAL = 0x00000001;
46 		// internal const uint TF_SFT_HIDDEN = 0x00000008;
47 
48 		/* [DllImport("KeePassNtv32.dll", EntryPoint = "TransformKey")]
49 		[return: MarshalAs(UnmanagedType.Bool)]
50 		private static extern bool TransformKey32(IntPtr pBuf256,
51 			IntPtr pKey256, UInt64 uRounds);
52 
53 		[DllImport("KeePassNtv64.dll", EntryPoint = "TransformKey")]
54 		[return: MarshalAs(UnmanagedType.Bool)]
55 		private static extern bool TransformKey64(IntPtr pBuf256,
56 			IntPtr pKey256, UInt64 uRounds);
57 
58 		internal static bool TransformKey(IntPtr pBuf256, IntPtr pKey256,
59 			UInt64 uRounds)
60 		{
61 			if(IntPtr.Size == 4)
62 				return TransformKey32(pBuf256, pKey256, uRounds);
63 			return TransformKey64(pBuf256, pKey256, uRounds);
64 		}
65 
66 		[DllImport("KeePassNtv32.dll", EntryPoint = "TransformKeyTimed")]
67 		[return: MarshalAs(UnmanagedType.Bool)]
68 		private static extern bool TransformKeyTimed32(IntPtr pBuf256,
69 			IntPtr pKey256, ref UInt64 puRounds, UInt32 uSeconds);
70 
71 		[DllImport("KeePassNtv64.dll", EntryPoint = "TransformKeyTimed")]
72 		[return: MarshalAs(UnmanagedType.Bool)]
73 		private static extern bool TransformKeyTimed64(IntPtr pBuf256,
74 			IntPtr pKey256, ref UInt64 puRounds, UInt32 uSeconds);
75 
76 		internal static bool TransformKeyTimed(IntPtr pBuf256, IntPtr pKey256,
77 			ref UInt64 puRounds, UInt32 uSeconds)
78 		{
79 			if(IntPtr.Size == 4)
80 				return TransformKeyTimed32(pBuf256, pKey256, ref puRounds, uSeconds);
81 			return TransformKeyTimed64(pBuf256, pKey256, ref puRounds, uSeconds);
82 		} */
83 
84 #if !KeePassUAP
85 		[DllImport("KeePassLibC32.dll", EntryPoint = "TransformKey256")]
86 		[return: MarshalAs(UnmanagedType.Bool)]
TransformKey32(IntPtr pBuf256, IntPtr pKey256, UInt64 uRounds)87 		private static extern bool TransformKey32(IntPtr pBuf256,
88 			IntPtr pKey256, UInt64 uRounds);
89 
90 		[DllImport("KeePassLibC64.dll", EntryPoint = "TransformKey256")]
91 		[return: MarshalAs(UnmanagedType.Bool)]
TransformKey64(IntPtr pBuf256, IntPtr pKey256, UInt64 uRounds)92 		private static extern bool TransformKey64(IntPtr pBuf256,
93 			IntPtr pKey256, UInt64 uRounds);
94 
TransformKey(IntPtr pBuf256, IntPtr pKey256, UInt64 uRounds)95 		internal static bool TransformKey(IntPtr pBuf256, IntPtr pKey256,
96 			UInt64 uRounds)
97 		{
98 			if(IntPtr.Size == 4)
99 				return TransformKey32(pBuf256, pKey256, uRounds);
100 			return TransformKey64(pBuf256, pKey256, uRounds);
101 		}
102 
103 		[DllImport("KeePassLibC32.dll", EntryPoint = "TransformKeyBenchmark256")]
TransformKeyBenchmark32(UInt32 uTimeMs)104 		private static extern UInt64 TransformKeyBenchmark32(UInt32 uTimeMs);
105 
106 		[DllImport("KeePassLibC64.dll", EntryPoint = "TransformKeyBenchmark256")]
TransformKeyBenchmark64(UInt32 uTimeMs)107 		private static extern UInt64 TransformKeyBenchmark64(UInt32 uTimeMs);
108 
TransformKeyBenchmark(UInt32 uTimeMs)109 		internal static UInt64 TransformKeyBenchmark(UInt32 uTimeMs)
110 		{
111 			if(IntPtr.Size == 4)
112 				return TransformKeyBenchmark32(uTimeMs);
113 			return TransformKeyBenchmark64(uTimeMs);
114 		}
115 #endif
116 
117 		/* [DllImport("KeePassLibC32.dll", EntryPoint = "TF_ShowLangBar")]
118 		[return: MarshalAs(UnmanagedType.Bool)]
119 		private static extern bool TF_ShowLangBar32(UInt32 dwFlags);
120 
121 		[DllImport("KeePassLibC64.dll", EntryPoint = "TF_ShowLangBar")]
122 		[return: MarshalAs(UnmanagedType.Bool)]
123 		private static extern bool TF_ShowLangBar64(UInt32 dwFlags);
124 
125 		internal static bool TfShowLangBar(uint dwFlags)
126 		{
127 			if(IntPtr.Size == 4) return TF_ShowLangBar32(dwFlags);
128 			return TF_ShowLangBar64(dwFlags);
129 		} */
130 
131 		[DllImport("KeePassLibC32.dll", EntryPoint = "ProtectProcessWithDacl")]
ProtectProcessWithDacl32()132 		private static extern void ProtectProcessWithDacl32();
133 
134 		[DllImport("KeePassLibC64.dll", EntryPoint = "ProtectProcessWithDacl")]
ProtectProcessWithDacl64()135 		private static extern void ProtectProcessWithDacl64();
136 
ProtectProcessWithDacl()137 		internal static void ProtectProcessWithDacl()
138 		{
139 			try
140 			{
141 				if(NativeLib.IsUnix()) return;
142 
143 				if(IntPtr.Size == 4) ProtectProcessWithDacl32();
144 				else ProtectProcessWithDacl64();
145 			}
146 			catch(Exception) { Debug.Assert(false); }
147 		}
148 
149 		[DllImport("Kernel32.dll", SetLastError = true)]
150 		[return: MarshalAs(UnmanagedType.Bool)]
CloseHandle(IntPtr hObject)151 		internal static extern bool CloseHandle(IntPtr hObject);
152 
153 		[DllImport("Kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false,
154 			SetLastError = true)]
155 		[return: MarshalAs(UnmanagedType.Bool)]
GetVolumeInformation(string lpRootPathName, StringBuilder lpVolumeNameBuffer, UInt32 nVolumeNameSize, ref UInt32 lpVolumeSerialNumber, ref UInt32 lpMaximumComponentLength, ref UInt32 lpFileSystemFlags, StringBuilder lpFileSystemNameBuffer, UInt32 nFileSystemNameSize)156 		internal static extern bool GetVolumeInformation(string lpRootPathName,
157 			StringBuilder lpVolumeNameBuffer, UInt32 nVolumeNameSize,
158 			ref UInt32 lpVolumeSerialNumber, ref UInt32 lpMaximumComponentLength,
159 			ref UInt32 lpFileSystemFlags, StringBuilder lpFileSystemNameBuffer,
160 			UInt32 nFileSystemNameSize);
161 
162 		[DllImport("Kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false,
163 			SetLastError = true)]
164 		[return: MarshalAs(UnmanagedType.Bool)]
MoveFileEx(string lpExistingFileName, string lpNewFileName, UInt32 dwFlags)165 		internal static extern bool MoveFileEx(string lpExistingFileName,
166 			string lpNewFileName, UInt32 dwFlags);
167 
168 		[DllImport("KtmW32.dll", CharSet = CharSet.Unicode, ExactSpelling = true,
169 			SetLastError = true)]
CreateTransaction(IntPtr lpTransactionAttributes, IntPtr lpUOW, UInt32 dwCreateOptions, UInt32 dwIsolationLevel, UInt32 dwIsolationFlags, UInt32 dwTimeout, string lpDescription)170 		internal static extern IntPtr CreateTransaction(IntPtr lpTransactionAttributes,
171 			IntPtr lpUOW, UInt32 dwCreateOptions, UInt32 dwIsolationLevel,
172 			UInt32 dwIsolationFlags, UInt32 dwTimeout, string lpDescription);
173 
174 		[DllImport("KtmW32.dll", SetLastError = true)]
175 		[return: MarshalAs(UnmanagedType.Bool)]
CommitTransaction(IntPtr hTransaction)176 		internal static extern bool CommitTransaction(IntPtr hTransaction);
177 
178 		[DllImport("Kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false,
179 			SetLastError = true)]
180 		[return: MarshalAs(UnmanagedType.Bool)]
MoveFileTransacted(string lpExistingFileName, string lpNewFileName, IntPtr lpProgressRoutine, IntPtr lpData, UInt32 dwFlags, IntPtr hTransaction)181 		internal static extern bool MoveFileTransacted(string lpExistingFileName,
182 			string lpNewFileName, IntPtr lpProgressRoutine, IntPtr lpData,
183 			UInt32 dwFlags, IntPtr hTransaction);
184 
185 		[DllImport("Shell32.dll")]
SHGetKnownFolderPath(ref Guid rfid, uint dwFlags, IntPtr hToken, out IntPtr ppszPath)186 		private static extern int SHGetKnownFolderPath(ref Guid rfid, uint dwFlags,
187 			IntPtr hToken, out IntPtr ppszPath);
188 
189 #if (!KeePassLibSD && !KeePassUAP)
190 		[DllImport("ShlWApi.dll", CharSet = CharSet.Auto)]
191 		[return: MarshalAs(UnmanagedType.Bool)]
PathRelativePathTo([Out] StringBuilder pszPath, [In] string pszFrom, uint dwAttrFrom, [In] string pszTo, uint dwAttrTo)192 		internal static extern bool PathRelativePathTo([Out] StringBuilder pszPath,
193 			[In] string pszFrom, uint dwAttrFrom, [In] string pszTo, uint dwAttrTo);
194 
195 		[DllImport("ShlWApi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
StrCmpLogicalW(string x, string y)196 		private static extern int StrCmpLogicalW(string x, string y);
197 
198 		private static bool? m_obSupportsLogicalCmp = null;
199 
TestNaturalComparisonsSupport()200 		private static void TestNaturalComparisonsSupport()
201 		{
202 			try
203 			{
204 				StrCmpLogicalW("0", "0"); // Throws exception if unsupported
205 				m_obSupportsLogicalCmp = true;
206 			}
207 			catch(Exception) { m_obSupportsLogicalCmp = false; }
208 		}
209 #endif
210 
211 		internal static bool SupportsStrCmpNaturally
212 		{
213 			get
214 			{
215 #if (!KeePassLibSD && !KeePassUAP)
216 				if(!m_obSupportsLogicalCmp.HasValue)
217 					TestNaturalComparisonsSupport();
218 
219 				return m_obSupportsLogicalCmp.Value;
220 #else
221 				return false;
222 #endif
223 			}
224 		}
225 
StrCmpNaturally(string x, string y)226 		internal static int StrCmpNaturally(string x, string y)
227 		{
228 #if (!KeePassLibSD && !KeePassUAP)
229 			if(!NativeMethods.SupportsStrCmpNaturally)
230 			{
231 				Debug.Assert(false);
232 				return string.Compare(x, y, true);
233 			}
234 
235 			return StrCmpLogicalW(x, y);
236 #else
237 			Debug.Assert(false);
238 			return string.Compare(x, y, true);
239 #endif
240 		}
241 
GetUserRuntimeDir()242 		internal static string GetUserRuntimeDir()
243 		{
244 #if KeePassLibSD
245 			return Path.GetTempPath();
246 #else
247 #if KeePassUAP
248 			string strRtDir = EnvironmentExt.AppDataLocalFolderPath;
249 #else
250 			string strRtDir = Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR");
251 			if(string.IsNullOrEmpty(strRtDir))
252 				strRtDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
253 			if(string.IsNullOrEmpty(strRtDir))
254 			{
255 				Debug.Assert(false);
256 				return Path.GetTempPath(); // Not UrlUtil (otherwise cyclic)
257 			}
258 #endif
259 
260 			strRtDir = UrlUtil.EnsureTerminatingSeparator(strRtDir, false);
261 			strRtDir += PwDefs.ShortProductName;
262 
263 			return strRtDir;
264 #endif
265 		}
266 
GetKnownFolderPath(Guid g)267 		internal static string GetKnownFolderPath(Guid g)
268 		{
269 			if(Marshal.SystemDefaultCharSize != 2) { Debug.Assert(false); return string.Empty; }
270 
271 			IntPtr pszPath = IntPtr.Zero;
272 			try
273 			{
274 				if(SHGetKnownFolderPath(ref g, 0, IntPtr.Zero, out pszPath) == 0)
275 				{
276 					if(pszPath != IntPtr.Zero)
277 						return Marshal.PtrToStringUni(pszPath);
278 					else { Debug.Assert(false); }
279 				}
280 			}
281 			catch(Exception) { Debug.Assert(false); }
282 			finally
283 			{
284 				try { if(pszPath != IntPtr.Zero) Marshal.FreeCoTaskMem(pszPath); }
285 				catch(Exception) { Debug.Assert(false); }
286 			}
287 
288 			return string.Empty;
289 		}
290 	}
291 }
292