307 lines
13 KiB
C#
307 lines
13 KiB
C#
//#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
|
|
//{
|
|
// /// <summary>
|
|
// /// This class contains various Windows system calls related to reading locked files.
|
|
// /// Some PInvoke signatures are from http://www.pinvoke.net
|
|
// /// </summary>
|
|
// 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
|
|
// );
|
|
|
|
// /// <summary>
|
|
// /// Opens a file with backup semantics, only works if the caller has the SeBackupPrivilege
|
|
// /// </summary>
|
|
// /// <param name="filename">The file to open</param>
|
|
// /// <returns>The opened backup filestream</returns>
|
|
// 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);
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// Internal helper function that returns two values relating to the SeBackupPrivilege
|
|
// /// </summary>
|
|
// /// <param name="hasPrivilege">True if the calling proccess has the SeBackupPrivilege, false otherwise</param>
|
|
// /// <param name="isEnabled">True if the SeBackupPrivilege is enabled, false otherwise</param>
|
|
// 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;
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// Gets a value indicating if the current process can set the SeBackupPrivilege value
|
|
// /// </summary>
|
|
// public static bool CanEnableBackupPrivilege
|
|
// {
|
|
// get
|
|
// {
|
|
// bool hasPrivilege, isEnabled;
|
|
// GetBackupPrivilege(out hasPrivilege, out isEnabled);
|
|
|
|
// return hasPrivilege;
|
|
// }
|
|
// }
|
|
|
|
// /// <summary>
|
|
// /// Gets or sets a value indicating if the current process has the backup privilege (SE_BACKUP_NAME)
|
|
// /// </summary>
|
|
// 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
|
|
|
|
// }
|
|
//}
|