//#region Disclaimer / License //// Copyright (C) 2015, 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 //// //using System.Security.AccessControl; //#endregion //using System; //using System.Text; //using System.Runtime.InteropServices; //using System.ComponentModel; //using Microsoft.Win32.SafeHandles; //namespace Duplicati.Library.IO //{ // /// // /// This class contains various Windows system calls related to reading locked files. // /// Some PInvoke signatures are from http://www.pinvoke.net // /// // public static class WinNativeMethods // { // [Flags] // private enum FileAccess : uint // { // GenericNone = 0x00000000, // GenericRead = 0x80000000, // GenericWrite = 0x40000000, // GenericExecute = 0x20000000, // GenericAll = 0x10000000, // ReadControl = 0x00020000 // } // [Flags] // private enum FileShare : uint // { // None = 0x00000000, // Read = 0x00000001, // Write = 0x00000002, // ReadWrite = 0x00000003, // Delete = 0x00000004 // } // private enum CreationDisposition : uint // { // New = 1, // CreateAlways = 2, // OpenExisting = 3, // OpenAlways = 4, // TruncateExisting = 5 // } // [Flags] // private enum FileAttributes : uint // { // Readonly = 0x00000001, // Hidden = 0x00000002, // System = 0x00000004, // Directory = 0x00000010, // Archive = 0x00000020, // Device = 0x00000040, // Normal = 0x00000080, // Temporary = 0x00000100, // SparseFile = 0x00000200, // ReparsePoint = 0x00000400, // Compressed = 0x00000800, // Offline = 0x00001000, // NotContentIndexed = 0x00002000, // Encrypted = 0x00004000, // Write_Through = 0x80000000, // Overlapped = 0x40000000, // NoBuffering = 0x20000000, // RandomAccess = 0x10000000, // SequentialScan = 0x08000000, // DeleteOnClose = 0x04000000, // BackupSemantics = 0x02000000, // PosixSemantics = 0x01000000, // OpenReparsePoint = 0x00200000, // OpenNoRecall = 0x00100000, // FirstPipeInstance = 0x00080000 // } // private const int TOKEN_ADJUST_PRIVILEGES = 0x00000020; // private const int TOKEN_QUERY = 0x00000008; // private const int SE_PRIVILEGE_ENABLED = 0x00000002; // private const string SE_BACKUP_NAME = "SeBackupPrivilege"; // private const string SE_RESTORE_NAME = "SeRestorePrivilege"; // private const int TOKEN_INFORMATION_CLASS_PRIVILEGES = 0x3; // private const int ATTRIBUTE_FIXED_SIZE = 200; // [StructLayout(LayoutKind.Sequential)] // private struct LUID // { // public UInt32 LowPart; // public Int32 HighPart; // } // [StructLayout(LayoutKind.Sequential)] // private struct LUID_AND_ATTRIBUTES // { // public LUID Luid; // public UInt32 Attributes; // } // [StructLayout(LayoutKind.Sequential)] // private struct TOKEN_PRIVILEGES // { // public UInt32 PrivilegeCount; // [MarshalAs(UnmanagedType.ByValArray, SizeConst = ATTRIBUTE_FIXED_SIZE)] //We make sure there is enough room // public LUID_AND_ATTRIBUTES[] Privileges; // } // [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] // private static extern int OpenProcessToken(int ProcessHandle, int DesiredAccess, ref int tokenhandle); // [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] // private static extern int GetCurrentProcess(); // [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] // private static extern int GetTokenInformation(int tokenhandle, int tokeninformationclass, [MarshalAs(UnmanagedType.Struct)]ref TOKEN_PRIVILEGES state, int bufferlength, ref int actualsize); // [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] // private static extern int LookupPrivilegeValue(string lpsystemname, string lpname, [MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid); // [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] // private static extern int AdjustTokenPrivileges(int tokenhandle, bool disableprivs, [MarshalAs(UnmanagedType.Struct)]ref TOKEN_PRIVILEGES newState, int bufferlength, [MarshalAs(UnmanagedType.Struct)]ref TOKEN_PRIVILEGES previousState, ref int actualsize); // [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] // private static extern int LookupPrivilegeName(string lpSystemName, [MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid, System.Text.StringBuilder lpName, ref int cchName); // [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] // private static extern SafeFileHandle CreateFile( // string lpFileName, // FileAccess dwDesiredAccess, // FileShare dwShareMode, // IntPtr lpSecurityAttributes, // CreationDisposition dwCreationDisposition, // FileAttributes dwFlagsAndAttributes, // IntPtr hTemplateFile // ); // /// // /// Opens a file with backup semantics, only works if the caller has the SeBackupPrivilege // /// // /// The file to open // /// The opened backup filestream // public static System.IO.Stream OpenAsBackupFile(string filename) // { // var hFile = CreateFile(filename, FileAccess.ReadControl, FileShare.None, IntPtr.Zero, CreationDisposition.OpenExisting, FileAttributes.BackupSemantics | FileAttributes.SequentialScan, IntPtr.Zero); // if (hFile.IsInvalid) // throw new Win32Exception(Marshal.GetLastWin32Error()); // //TODO: We need to be able to seek to pos 0 // return new Alphaleonis.Win32.Filesystem.BackupFileStream(hFile, FileSystemRights.Read); // } // /// // /// Internal helper function that returns two values relating to the SeBackupPrivilege // /// // /// True if the calling proccess has the SeBackupPrivilege, false otherwise // /// True if the SeBackupPrivilege is enabled, false otherwise // private static void GetBackupPrivilege(out bool hasPrivilege, out bool isEnabled) // { // int token = 0; // int outsize = 0; // TOKEN_PRIVILEGES TP = new TOKEN_PRIVILEGES(); // LUID backupLuid = new LUID(); // if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref token) == 0) // throw new Win32Exception(Marshal.GetLastWin32Error()); // if (LookupPrivilegeValue(null, SE_BACKUP_NAME, ref backupLuid) == 0) // throw new Win32Exception(Marshal.GetLastWin32Error()); // if (GetTokenInformation(token, TOKEN_INFORMATION_CLASS_PRIVILEGES, ref TP, Marshal.SizeOf(typeof(TOKEN_PRIVILEGES)), ref outsize) == 0) // throw new Win32Exception(Marshal.GetLastWin32Error()); //#if DEBUG // Console.WriteLine("Read token information:"); // PrintTokenInformation(TP); //#endif // for (int i = 0; i < TP.PrivilegeCount; i++) // if (TP.Privileges[i].Luid.LowPart == backupLuid.LowPart && TP.Privileges[i].Luid.HighPart == backupLuid.HighPart) // { // isEnabled = (TP.Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) == SE_PRIVILEGE_ENABLED; // hasPrivilege = true; // return; // } // hasPrivilege = false; // isEnabled = false; // } // /// // /// Gets a value indicating if the current process can set the SeBackupPrivilege value // /// // public static bool CanEnableBackupPrivilege // { // get // { // bool hasPrivilege, isEnabled; // GetBackupPrivilege(out hasPrivilege, out isEnabled); // return hasPrivilege; // } // } // /// // /// Gets or sets a value indicating if the current process has the backup privilege (SE_BACKUP_NAME) // /// // public static bool BackupPrivilege // { // get // { // bool hasPrivilege, isEnabled; // GetBackupPrivilege(out hasPrivilege, out isEnabled); // //if (!hasPrivilege) // //throw new Duplicati.Library.Interface.UserInformationException(Strings.WinNativeMethod.MissingBackupPrivilegeError, "MissingBackupPrivilege"); // return isEnabled; // } // set // { // //if (!CanEnableBackupPrivilege) // //throw new Duplicati.Library.Interface.UserInformationException(Strings.WinNativeMethod.MissingBackupPrivilegeError, "MissingBackupPrivilege"); // int token = 0; // int outsize = 0; // TOKEN_PRIVILEGES TP = new TOKEN_PRIVILEGES(); // LUID backupLuid = new LUID(); // LUID restoreLuid = new LUID(); // if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref token) == 0) // throw new Win32Exception(Marshal.GetLastWin32Error()); // if (LookupPrivilegeValue(null, SE_BACKUP_NAME, ref backupLuid) == 0) // throw new Win32Exception(Marshal.GetLastWin32Error()); // if (LookupPrivilegeValue(null, SE_RESTORE_NAME, ref restoreLuid) == 0) // throw new Win32Exception(Marshal.GetLastWin32Error()); // TP.PrivilegeCount = 1; // TP.Privileges = new LUID_AND_ATTRIBUTES[ATTRIBUTE_FIXED_SIZE]; // TP.Privileges[0].Attributes = value ? SE_PRIVILEGE_ENABLED : 0u; // TP.Privileges[0].Luid = backupLuid; // TP.Privileges[1].Attributes = value ? SE_PRIVILEGE_ENABLED : 0u; // TP.Privileges[1].Luid = restoreLuid; // TOKEN_PRIVILEGES TPOut = new TOKEN_PRIVILEGES(); // if (AdjustTokenPrivileges(token, false, ref TP, Marshal.SizeOf(typeof(TOKEN_PRIVILEGES)), ref TPOut, ref outsize) == 0) // throw new Win32Exception(Marshal.GetLastWin32Error()); //#if DEBUG // Console.WriteLine("Modified token information:"); // PrintTokenInformation(TPOut); //#endif // if (Marshal.GetLastWin32Error() != 0) // throw new Win32Exception(Marshal.GetLastWin32Error()); // } // } //#if DEBUG // private static void PrintTokenInformation(TOKEN_PRIVILEGES tp) // { // int outsize; // StringBuilder sbname = new StringBuilder(1024 * 4); // for (int i = 0; i < tp.PrivilegeCount; i++) // { // LUID id = tp.Privileges[i].Luid; // outsize = sbname.Capacity; // if (LookupPrivilegeName(null, ref id, sbname, ref outsize) == 0) // Console.WriteLine("Invalid LUID {0}:{1}: {2}", id.HighPart, id.LowPart, new Win32Exception(Marshal.GetLastWin32Error()).Message); // else // Console.WriteLine("{0}, status {1}", sbname, tp.Privileges[i].Attributes); // } // } //#endif // } //}