/*
Copyright (c) Microsoft Corporation
All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License
at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions and
limitations under the License.
*/
//------------------------------------------------------------------------------
//
// Wrapped native methods
//
//------------------------------------------------------------------------------
namespace Microsoft.Research.Dryad
{
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.ConstrainedExecution;
using System.Security;
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles;
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
public sealed class SafeThreadHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeThreadHandle() : base(true) { }
public SafeThreadHandle(IntPtr handle)
: base(false)
{
this.SetHandle(handle);
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return NativeMethods.CloseHandle(this.handle);
}
}
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
public sealed class SafeProcessHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeProcessHandle() : base(true) { }
public SafeProcessHandle(IntPtr handle)
: base(false)
{
this.SetHandle(handle);
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return NativeMethods.CloseHandle(this.handle);
}
}
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
public sealed class SafeImpersonationToken : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeImpersonationToken() : base(true) { }
public SafeImpersonationToken(IntPtr token)
: base(false)
{
this.SetHandle(token);
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return NativeMethods.CloseHandle(this.handle);
}
}
///
/// Wrapped native methods
///
[SuppressUnmanagedCodeSecurity]
public static class NativeMethods
{
public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
// Create process
public const uint CREATE_UNICODE_ENVIRONMENT = 0x00000400;
public const uint CREATE_SUSPENDED = 0x00000004;
public const uint CREATE_BREAKAWAY_FROM_JOB = 0x01000000;
public const uint CREATE_NO_WINDOW = 0x08000000;
// LogonUser
public const uint LOGON32_LOGON_INTERACTIVE = 0x00000002;
public const uint LOGON32_LOGON_NETWORK = 0x00000003;
public const uint LOGON32_LOGON_BATCH = 0x00000004;
public const uint LOGON32_LOGON_NETWORK_CLEARTEXT = 0x00000008;
public const uint LOGON32_PROVIDER_DEFAULT = 0x00000000;
///
/// Error flag for "no error"
///
public const int ERROR_OK = 0;
///
/// Error flag for insufficient buffer
///
public const int ERROR_INSUFFICIENT_BUFFER = 122;
// Job object
public const int JobObjectExtendedLimitInformationClass = 9;
public const uint JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000;
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct JobObjectExtendedLimitInformation
{
public Int64 PerProcessUserTimeLimit;
public Int64 PerJobUserTimeLimit;
public UInt32 LimitFlags;
public UIntPtr MinimumWorkingSetSize;
public UIntPtr MaximumWorkingSetSize;
public UInt32 ActiveProcessLimit;
public IntPtr Affinity;
public UInt32 PriorityClass;
public UInt32 SchedulingClass;
public UInt64 ReadOperationCount;
public UInt64 WriteOperationCount;
public UInt64 OtherOperationCount;
public UInt64 ReadTransferCount;
public UInt64 WriteTransferCount;
public UInt64 OtherTransferCount;
public UIntPtr ProcessMemoryLimit;
public UIntPtr JobMemoryLimit;
public UIntPtr PeakProcessMemoryUsed;
public UIntPtr PeakJobMemoryUsed;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public UInt32 nLength;
public UIntPtr lpSecurityAttributes;
}
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CreateProcess([MarshalAs(UnmanagedType.LPTStr)]string lpApplicationName,
StringBuilder lpCommandLine, IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes, bool bInheritHandles,
uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,
[In] ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("Advapi32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CreateProcessAsUser(SafeImpersonationToken hToken, [MarshalAs(UnmanagedType.LPTStr)]string lpApplicationName,
StringBuilder lpCommandLine, IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes, bool bInheritHandles,
uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,
[In] ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("Advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public extern static bool LogonUser(string lpszUserName, string lpszDomain, string lpszPassword,
uint dwLogonType, uint dwLogonProvider, out SafeImpersonationToken phToken
);
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetExitCodeProcess(SafeProcessHandle hProcess, out uint lpExitCode);
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool TerminateProcess(SafeProcessHandle hProcess, int uExitCode);
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
public static extern uint ResumeThread(SafeThreadHandle hThread);
[DllImport("kernel32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr CreateJobObject(IntPtr lpJobAttributes, string lpName);
public const int JobObjectExtendedLimitInformationQuery = 9;
public const int JobObjectExtendedLimitInformationSet = 9;
public const int QueryJobObjectBasicProcessIdList = 3;
[StructLayout(LayoutKind.Sequential)]
public struct JobObjectBasicProcessIdListHeader
{
public UInt32 NumberOfAssignedProcesses;
public UInt32 NumberOfProcessIdsInList;
}
[DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public extern static bool QueryInformationJobObject(
IntPtr hJob,
int query,
out JobObjectExtendedLimitInformation info,
int size,
out int returnedSize
);
[DllImport("kernel32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public extern static bool SetInformationJobObject(IntPtr hJob, int informationClass, [In] ref JobObjectExtendedLimitInformation info, int size);
[DllImport("kernel32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public extern static bool AssignProcessToJobObject(IntPtr hJob, SafeProcessHandle hProcess);
[DllImport("kernel32.dll", SetLastError = true)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public extern static bool CloseHandle(IntPtr handle);
[DllImport("kernel32.dll", SetLastError = true)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public extern static bool CloseHandle(HandleRef handleRef);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static void SafeCloseValidHandle(HandleRef handleRef)
{
if (handleRef.Handle != IntPtr.Zero && handleRef.Handle != INVALID_HANDLE_VALUE)
{
try
{
CloseHandle(handleRef);
}
catch
{
// Swallow exception
}
}
}
///
/// contains information about the current state of both physical and virtual memory, including extended memory
///
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class MEMORYSTATUSEX
{
///
/// Size of the structure, in bytes. You must set this member before calling GlobalMemoryStatusEx.
///
public uint dwLength;
///
/// Number between 0 and 100 that specifies the approximate percentage of physical memory that is in use (0 indicates no memory use and 100 indicates full memory use).
///
public uint dwMemoryLoad;
///
/// Total size of physical memory, in bytes.
///
public ulong ullTotalPhys;
///
/// Size of physical memory available, in bytes.
///
public ulong ullAvailPhys;
///
/// Size of the committed memory limit, in bytes. This is physical memory plus the size of the page file, minus a small overhead.
///
public ulong ullTotalPageFile;
///
/// Size of available memory to commit, in bytes. The limit is ullTotalPageFile.
///
public ulong ullAvailPageFile;
///
/// Total size of the user mode portion of the virtual address space of the calling process, in bytes.
///
public ulong ullTotalVirtual;
///
/// Size of unreserved and uncommitted memory in the user mode portion of the virtual address space of the calling process, in bytes.
///
public ulong ullAvailVirtual;
///
/// Size of unreserved and uncommitted memory in the extended portion of the virtual address space of the calling process, in bytes.
///
public ulong ullAvailExtendedVirtual;
///
/// Initializes a new instance of the class.
///
public MEMORYSTATUSEX()
{
this.dwLength = (uint)Marshal.SizeOf(typeof(NativeMethods.MEMORYSTATUSEX));
}
}
///
/// Retrieves information about the system's current usage of both physical and virtual memory.
///
/// A pointer to a MEMORYSTATUSEX structure that receives information about current memory availability
/// If the function succeeds, the return value is nonzero. Error code otherwise.
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);
///
/// Retrieves information about the amount of space that is available on a disk volume, which is the total amount of space,
/// the total amount of free space, and the total amount of free space available to the user that is associated with the calling thread.
///
/// A directory on the disk.
/// A pointer to a variable that receives the total number of free bytes on a disk that are available to the user who is associated with the calling thread.
/// A pointer to a variable that receives the total number of bytes on a disk that are available to the user who is associated with the calling thread.
/// A pointer to a variable that receives the total number of free bytes on a disk.
///
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool GetDiskFreeSpaceEx(string lpDirectoryName,
out ulong lpFreeBytesAvailable,
out ulong lpTotalNumberOfBytes,
out ulong lpTotalNumberOfFreeBytes);
///
/// SID Usage Enum
///
public enum SID_NAME_USE
{
SidTypeUser = 1,
SidTypeGroup,
SidTypeDomain,
SidTypeAlias,
SidTypeWellKnownGroup,
SidTypeDeletedAccount,
SidTypeInvalid,
SidTypeUnknown,
SidTypeComputer
}
///
/// Get SID for account name
///
/// Compute name
/// Account name
/// Security ID
/// Number of bytes needed to hold the SID
/// Domain name reference by SID
/// Number of bytes needed to hold the domain
/// Account type
/// error flag
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool LookupAccountName(
string lpSystemName,
string lpAccountName,
[MarshalAs(UnmanagedType.LPArray)] byte[] Sid,
ref uint cbSid,
StringBuilder ReferencedDomainName,
ref uint cchReferencedDomainName,
out SID_NAME_USE peUse);
///
/// Retrieves the name of the account for this SID and the name of the first domain on which this SID is found
///
/// string that specifies the target computer
/// the SID to look up
/// buffer that receives the account name that corresponds to the Sid parameter
/// On input, specifies the size of the lpName buffer. If the function fails because
/// the buffer is too small or if cchName is zero, cchName receives the required buffer size
/// buffer that receives the name of the domain where the account name was found.
/// Same as cchName, but for the domain string buffer
/// pointer to a variable that receives a SID_NAME_USE value that indicates the type of the account
/// If the function succeeds, the function returns nonzero.If the function fails, it returns zero
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool LookupAccountSid(
string lpSystemName,
[MarshalAs(UnmanagedType.LPArray)] byte[] Sid,
StringBuilder lpName,
ref uint cchName,
StringBuilder ReferencedDomainName,
ref uint cchReferencedDomainName,
out SID_NAME_USE peUse);
///
/// Converts a security ID pointer to the string value
///
/// pointer to SID
/// string value
/// error flag
[DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool ConvertSidToStringSid(
[MarshalAs(UnmanagedType.LPArray)] byte[] pSID,
out IntPtr ptrSid);
///
/// Frees a pointer
///
/// pointer to free
/// error flag
[DllImport("kernel32.dll")]
public static extern IntPtr LocalFree(IntPtr hMem);
}
}