/// <summary> /// Gets the name of the user for the <paramref name="process"/> given. /// </summary> /// <param name="process">Process to get username for.</param> /// <returns>Name of the user for the <paramref name="process"/> in the <c>DOMAIN\username</c> format.</returns> /// <exception cref="ArgumentNullException"><paramref name="process"/> is <see langword="null"/>.</exception> /// <exception cref="InvalidOperationException"> /// Process token cannot be obtained. /// <para>-or-</para> /// Process token information cannot be retrieved. /// <para>-or-</para> /// Account information cannot be found. /// </exception> public static string GetUserNameForProcess(Process process) { if (process == null) { throw new ArgumentNullException(nameof(process)); } SafeTokenHandle tokenHandle; if (!NativeMethods.OpenProcessToken(process.Handle, TokenAccessRights.TokenQuery, out tokenHandle)) { int hr = Marshal.GetHRForLastWin32Error(); throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to open process token: 0x{0:X8}", hr), Marshal.GetExceptionForHR(hr)); } using (tokenHandle) using (ResizableBuffer buffer = new ResizableBuffer(ProcessHelper.DefaultBufferSize)) { int actualSize; if (!NativeMethods.GetTokenInformation(tokenHandle, TokenInformationClass.TokenUser, buffer.DangerousGetPointer(), buffer.ByteLength, out actualSize)) { int hr = Marshal.GetHRForLastWin32Error(); if (hr != NativeMethods.ErrorInsufficientBuffer) { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to get token information: 0x{0:X8}", hr), Marshal.GetExceptionForHR(hr)); } // Resize and retry. buffer.Resize(actualSize); if (!NativeMethods.GetTokenInformation(tokenHandle, TokenInformationClass.TokenUser, buffer.DangerousGetPointer(), buffer.ByteLength, out actualSize)) { hr = Marshal.GetHRForLastWin32Error(); throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to get token information: 0x{0:X8}", hr), Marshal.GetExceptionForHR(hr)); } } TokenUser tokenUser = (TokenUser)Marshal.PtrToStructure(buffer.DangerousGetPointer(), typeof(TokenUser)); return(ProcessHelper.GetUserNameForSid(tokenUser.User.Sid)); } }
private void ProcessNotification(ResizableBuffer resizableBuffer) { IntPtr bufferPointer = resizableBuffer.DangerousGetPointer(); // Marshal the notification received. DriverNotificationHeader header = (DriverNotificationHeader)Marshal.PtrToStructure(bufferPointer, typeof(DriverNotificationHeader)); DriverNotification notification = new DriverNotification { Type = header.Type, DataLength = header.DataLength, Data = bufferPointer + this.notificationHeaderSize }; // Get the reply object from the user-defined handler. object reply = null; int handlerResult = (int)NativeMethods.Ok; try { reply = this.handler(notification); } catch (Exception e) { handlerResult = Marshal.GetHRForException(e); NotificationsMonitor.Logger.Error(e, "Notification handler threw an exception."); } // Driver is not expecting any reply. if (header.ReplyLength == 0) { if (reply != null) { NotificationsMonitor.Logger.Warn(CultureInfo.InvariantCulture, "Driver is not expecting any reply, but reply object is returned from handler: {0}", reply.GetType()); } return; } int replySize = this.replyHeaderSize + MarshalingHelper.GetObjectSize(reply); if (replySize > header.ReplyLength) { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Reply ({0} bytes) is bigger than the one expected by the driver ({1} bytes).", replySize, header.ReplyLength)); } DriverReplyHeader replyHeader = new DriverReplyHeader { MessageId = header.MessageId, // Notify driver about the exception thrown, if any. Status = handlerResult }; // Adjust the buffer to fit the reply. resizableBuffer.Resize(replySize); bufferPointer = resizableBuffer.DangerousGetPointer(); // Marshal reply to the output buffer. MarshalingHelper.MarshalObjectsToPointer(bufferPointer, replySize, replyHeader, reply); // And send it to the driver. uint hr = NativeMethods.FilterReplyMessage(this.filterPortHandle, bufferPointer, (uint)replySize); if (hr != NativeMethods.Ok) { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to send reply: 0x{0:X8}", hr), Marshal.GetExceptionForHR(unchecked((int)hr))); } }
private bool GetNextNotification(ResizableBuffer resizableBuffer, ManualResetEvent resetEvent, NativeOverlapped overlapped) { uint numberOfBytesTransferred; IntPtr completionKey; NativeOverlapped nativeOverlapped; // Buffer to marshal the notification into. IntPtr notificationBuffer = resizableBuffer.DangerousGetPointer(); resetEvent.Reset(); // // 'Asynchronously' request and get a message from the driver. // // FilterGetMessage returns ERROR_IO_PENDING, if it's set to operate in the asynchronous mode. uint hr = NativeMethods.FilterGetMessage(this.filterPortHandle, notificationBuffer, this.bufferSize, ref overlapped); if (hr != NativeMethods.Ok && hr != NativeMethods.ErrorIoPending) { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to request for a message: 0x{0:X8}", hr), Marshal.GetExceptionForHR(unchecked((int)hr))); } // If we don't specify timeout, this method will wait forever, but we want to be able to react on the task cancellation. while (!NativeMethods.GetQueuedCompletionStatus(this.completionPortHandle.DangerousGetHandle(), out numberOfBytesTransferred, out completionKey, out nativeOverlapped, NotificationsMonitor.QueueTimeout)) { hr = unchecked((uint)Marshal.GetHRForLastWin32Error()); // Break on the task cancellation. if (this.token.IsCancellationRequested) { break; } // If the WAIT_TIMEOUT is returned, there was no notification available and we want to wait again. if (hr == NativeMethods.WaitTimeout) { continue; } // If the I/O was cancelled on the completion port, or the completion port was closed. throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Invalid completion status: 0x{0:X8}", hr), Marshal.GetExceptionForHR(unchecked((int)hr))); } // If the current task was cancelled, the token wait handle will be set. // The 'resetEvent' will be set via the overlapped' structure, when the driver finishes writing notification to the buffer. return WaitHandle.WaitAny(new[] { this.token.WaitHandle, resetEvent }) == 1; }
public void DoWork() { // Notification buffer must also include a message header. This also validates the 'this.bufferSize' parameter. // The 'resetEvent' will be set by the I/O completion port via the OVERLAPPED structure when notification is available. using (ResizableBuffer resizableBuffer = new ResizableBuffer(this.notificationHeaderSize + this.bufferSize)) using (ManualResetEvent resetEvent = new ManualResetEvent(false)) { // This OVERLAPPED structure will be passed to the 'FilterGetMessage' method, so it'll operate in the asynchronous mode. NativeOverlapped overlapped = new NativeOverlapped { EventHandle = resetEvent.SafeWaitHandle.DangerousGetHandle() }; try { // Get the next notification and store it into the 'resizableBuffer'. while (this.GetNextNotification(resizableBuffer, resetEvent, overlapped)) { // Get the reply and send it back to the driver. this.ProcessNotification(resizableBuffer); } } finally { this.CancelIo(overlapped); } } }
/// <summary> /// Gets the name of the user for the <paramref name="process"/> given. /// </summary> /// <param name="process">Process to get username for.</param> /// <returns>Name of the user for the <paramref name="process"/> in the <c>DOMAIN\username</c> format.</returns> /// <exception cref="ArgumentNullException"><paramref name="process"/> is <see langword="null"/>.</exception> /// <exception cref="InvalidOperationException"> /// Process token cannot be obtained. /// <para>-or-</para> /// Process token information cannot be retrieved. /// <para>-or-</para> /// Account information cannot be found. /// </exception> public static string GetUserNameForProcess(Process process) { if (process == null) { throw new ArgumentNullException(nameof(process)); } SafeTokenHandle tokenHandle; if (!NativeMethods.OpenProcessToken(process.Handle, TokenAccessRights.TokenQuery, out tokenHandle)) { int hr = Marshal.GetHRForLastWin32Error(); throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to open process token: 0x{0:X8}", hr), Marshal.GetExceptionForHR(hr)); } using (tokenHandle) using (ResizableBuffer buffer = new ResizableBuffer(ProcessHelper.DefaultBufferSize)) { int actualSize; if (!NativeMethods.GetTokenInformation(tokenHandle, TokenInformationClass.TokenUser, buffer.DangerousGetPointer(), buffer.ByteLength, out actualSize)) { int hr = Marshal.GetHRForLastWin32Error(); if (hr != NativeMethods.ErrorInsufficientBuffer) { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to get token information: 0x{0:X8}", hr), Marshal.GetExceptionForHR(hr)); } // Resize and retry. buffer.Resize(actualSize); if (!NativeMethods.GetTokenInformation(tokenHandle, TokenInformationClass.TokenUser, buffer.DangerousGetPointer(), buffer.ByteLength, out actualSize)) { hr = Marshal.GetHRForLastWin32Error(); throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to get token information: 0x{0:X8}", hr), Marshal.GetExceptionForHR(hr)); } } TokenUser tokenUser = (TokenUser)Marshal.PtrToStructure(buffer.DangerousGetPointer(), typeof(TokenUser)); return ProcessHelper.GetUserNameForSid(tokenUser.User.Sid); } }
/// <summary> /// Sets the reparse point data for the <paramref name="path"/> given. /// </summary> /// <param name="path">File or directory to set the reparse point data for.</param> /// <param name="data"> /// Reparse point data to be set. /// It should be a value type, or an <see cref="IEnumerable"/>, and it should not contain /// reparse point data header information, because this function handles it separately. /// </param> /// <param name="reparseTag">Reparse point tag.</param> /// <param name="reparseGuid">Reparse point <see cref="Guid"/>. Must be specified, if the <paramref name="reparseTag"/> is a non-Microsoft tag.</param> /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/> or empty.</exception> /// <exception cref="ArgumentException"> /// <paramref name="data"/> is not a collection or a value type. /// <para>-or-</para> /// <paramref name="reparseTag"/> is a Microsoft tag, but the <paramref name="reparseGuid"/> is not <see langword="null"/>. /// <para>-or-</para> /// <paramref name="reparseTag"/> is a non-Microsoft tag, but the <paramref name="reparseGuid"/> is <see langword="null"/>. /// </exception> /// <exception cref="InvalidOperationException"> /// Reparse point <paramref name="data"/> cannot be set for the <paramref name="path"/>. /// </exception> /// <exception cref="IOException"> /// <paramref name="path"/> cannot be accessed. /// </exception> /// <remarks> /// This method will <i>NOT</i> update file attributes.<br/> /// For example, the <see cref="FileAttributes.ReparsePoint"/> will not be set. /// </remarks> public static void SetReparsePointData(string path, object data, int reparseTag, Guid?reparseGuid) { if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException(nameof(path)); } ReparsePointHelper.ValidateTagAndGuid(reparseTag, reparseGuid); bool isMicrosoftTag = ReparsePointHelper.IsMicrosoftTag(reparseTag); string normalizedPath = LongPathCommon.NormalizePath(path); if (!LongPathCommon.Exists(normalizedPath)) { throw new IOException(string.Format(CultureInfo.InvariantCulture, "{0} cannot be found.", path)); } using (SafeFileHandle handle = NativeMethods.CreateFile( normalizedPath, AccessRights.GenericWrite, FileShare.None, IntPtr.Zero, FileMode.Open, EFileAttributes.OpenReparsePoint | EFileAttributes.BackupSemantics, IntPtr.Zero)) { if (handle.IsInvalid) { Exception nativeException = Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()); throw new IOException(string.Format(CultureInfo.InvariantCulture, "Unable to open: {0}", path), nativeException); } int dataSize = MarshalingHelper.GetObjectSize(data); object header = isMicrosoftTag ? (object)new ReparseDataBufferHeader { ReparseDataLength = unchecked ((ushort)dataSize), ReparseTag = reparseTag } : new ReparseGuidDataBufferHeader { ReparseDataLength = unchecked ((ushort)dataSize), ReparseTag = reparseTag, ReparseGuid = reparseGuid.Value }; int headerSize = Marshal.SizeOf(header); int tagDataLength = headerSize + dataSize; using (ResizableBuffer buffer = new ResizableBuffer(Math.Max(ReparsePointHelper.BufferSize, tagDataLength))) { MarshalingHelper.MarshalObjectToPointer(new[] { header, data }, buffer.DangerousGetPointer()); // Set the reparse point data. int bytesReturned; bool success = NativeMethods.DeviceIoControl( handle, ReparsePointHelper.SetReparsePointControlCode, buffer.DangerousGetPointer(), tagDataLength, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero); if (!success) { Exception nativeException = Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()); throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to set the reparse point data: {0}", path), nativeException); } } } }
/// <summary> /// Gets the reparse point data from the <paramref name="path"/> given. /// </summary> /// <typeparam name="T"> /// Reparse point buffer data type. /// It should not contain reparse point data header information, because this function handles it separately. /// </typeparam> /// <param name="path">Path to the reparse point to get data from.</param> /// <param name="reparseTag">Reparse point tag.</param> /// <param name="reparseGuid">Reparse point <see cref="Guid"/>. Must be specified, if the <paramref name="reparseTag"/> is a non-Microsoft tag.</param> /// <returns>Reparse point data found.</returns> /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/> or empty.</exception> /// <exception cref="ArgumentException"> /// <paramref name="reparseTag"/> is a Microsoft tag, but the <paramref name="reparseGuid"/> is not <see langword="null"/>. /// <para>-or-</para> /// <paramref name="reparseTag"/> is a non-Microsoft tag, but the <paramref name="reparseGuid"/> is <see langword="null"/>. /// </exception> /// <exception cref="InvalidOperationException"> /// <paramref name="path"/> cannot be found. /// <para>-or-</para> /// <paramref name="path"/> is not a reparse point. /// <para>-or-</para> /// <paramref name="path"/> reparse point cannot be opened. /// <para>-or-</para> /// <paramref name="path"/> reparse point data cannot be retrieved. /// <para>-or-</para> /// <paramref name="path"/> reparse point tag or GUID is invalid. /// </exception> /// <remarks> /// See <c>http://msdn.microsoft.com/en-us/library/windows/desktop/aa365511(v=vs.85).aspx</c> for more details about reparse point tags. /// </remarks> public static T GetReparsePointData <T>(string path, int reparseTag, Guid?reparseGuid) where T : struct { if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException(nameof(path)); } ReparsePointHelper.ValidateTagAndGuid(reparseTag, reparseGuid); bool isMicrosoftTag = ReparsePointHelper.IsMicrosoftTag(reparseTag); string normalizedPath = LongPathCommon.NormalizePath(path); bool isDirectory; if (!LongPathCommon.Exists(normalizedPath, out isDirectory)) { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Path does not exist: {0}", path)); } // Check, whether the path given is a reparse point. FileAttributes attributes = isDirectory ? new LongPathDirectoryInfo(normalizedPath).Attributes : LongPathFile.GetAttributes(normalizedPath); if (!attributes.HasFlag(FileAttributes.ReparsePoint)) { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Path given is not a reparse point: {0}", path)); } using (SafeFileHandle handle = NativeMethods.CreateFile( normalizedPath, AccessRights.GenericRead, FileShare.Read, IntPtr.Zero, FileMode.Open, EFileAttributes.OpenReparsePoint | EFileAttributes.BackupSemantics, IntPtr.Zero)) { if (handle.IsInvalid) { Exception nativeException = Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()); throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to open reparse point: {0}", path), nativeException); } // Make sure that the buffer will be large enough to hold reparse point data. int initialBufferSize = Math.Max(ReparsePointHelper.BufferSize, Marshal.SizeOf(typeof(ReparseGuidDataBufferHeader)) + Marshal.SizeOf(typeof(T))); using (ResizableBuffer buffer = new ResizableBuffer(initialBufferSize)) { // Query the reparse point data. int bytesReturned; bool success = NativeMethods.DeviceIoControl( handle, ReparsePointHelper.GetReparsePointControlCode, IntPtr.Zero, 0, buffer.DangerousGetPointer(), buffer.ByteLength, out bytesReturned, IntPtr.Zero); int headerSize = isMicrosoftTag ? Marshal.SizeOf(typeof(ReparseDataBufferHeader)) : Marshal.SizeOf(typeof(ReparseGuidDataBufferHeader)); if (!success) { int hr = Marshal.GetHRForLastWin32Error(); if (hr != NativeMethods.ErrorMoreData) { Exception nativeException = Marshal.GetExceptionForHR(hr); throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to get the reparse point data: {0}", path), nativeException); } // Read the ReparseDataLength value, and resize buffer to fit the data. int dataSize = headerSize + Marshal.ReadInt16(buffer.DangerousGetPointer(), 4 /* sizeof(uint) */); buffer.Resize(dataSize); success = NativeMethods.DeviceIoControl( handle, ReparsePointHelper.GetReparsePointControlCode, IntPtr.Zero, 0, buffer.DangerousGetPointer(), buffer.ByteLength, out bytesReturned, IntPtr.Zero); if (!success) { Exception nativeException = Marshal.GetExceptionForHR(hr); throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Unable to get the reparse point data: {0}", path), nativeException); } } // Make sure that the reparse tag is correct. uint tag = unchecked ((uint)Marshal.ReadInt32(buffer.DangerousGetPointer())); if (tag != unchecked ((uint)reparseTag)) { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Reparse point tag is invalid. Path has 0x{0:X8}, but 0x{1:X8} is specified.", tag, reparseTag)); } // Make sure that the reparse point GUID is correct, if needed. if (!isMicrosoftTag) { ReparseGuidDataBufferHeader header = (ReparseGuidDataBufferHeader)Marshal.PtrToStructure(buffer.DangerousGetPointer(), typeof(ReparseGuidDataBufferHeader)); if (header.ReparseGuid != reparseGuid) { throw new InvalidOperationException(string.Format( CultureInfo.InvariantCulture, "Reparse point GUID is invalid. Path has {0}, but {1} is specified.", header.ReparseGuid.ToString("N"), reparseGuid.Value.ToString("N"))); } } return((T)Marshal.PtrToStructure(buffer.DangerousGetPointer() + headerSize, typeof(T))); } } }
public IEnumerable<FilterInfo> GetFiltersInformation() { List<FilterInfo> result = new List<FilterInfo>(); lock (this.syncRoot) { using (ResizableBuffer buffer = new ResizableBuffer(1024)) { IntPtr filterFindHandle = IntPtr.Zero; uint hr = 0; try { uint bytesReturned; hr = NativeMethods.FilterFindFirst(NativeMethods.FilterInformationClass.FilterAggregateStandardInformation, buffer.DangerousGetPointer(), (uint)buffer.ByteLength, out bytesReturned, out filterFindHandle); // If the buffer allocated is not large enough to hold all data returned, resize it and try again. if (hr == NativeMethods.ErrorInsufficientBuffer) { buffer.Resize(unchecked((int)bytesReturned)); hr = NativeMethods.FilterFindFirst(NativeMethods.FilterInformationClass.FilterAggregateStandardInformation, buffer.DangerousGetPointer(), (uint)buffer.ByteLength, out bytesReturned, out filterFindHandle); } if (hr != NativeMethods.Ok) { // There are no filters available. if (hr == NativeMethods.ErrorNoMoreItems) { return result; } throw Marshal.GetExceptionForHR(unchecked((int)hr)); } result.AddRange(FltmcManager.MarshalFilterInfo(buffer.DangerousGetPointer())); while (true) { hr = NativeMethods.FilterFindNext(filterFindHandle, NativeMethods.FilterInformationClass.FilterAggregateStandardInformation, buffer.DangerousGetPointer(), (uint)buffer.ByteLength, out bytesReturned); if (hr == NativeMethods.ErrorInsufficientBuffer) { buffer.Resize(unchecked((int)bytesReturned)); hr = NativeMethods.FilterFindNext(filterFindHandle, NativeMethods.FilterInformationClass.FilterAggregateStandardInformation, buffer.DangerousGetPointer(), (uint)buffer.ByteLength, out bytesReturned); } if (hr != NativeMethods.Ok) { if (hr == NativeMethods.ErrorNoMoreItems) { break; } throw Marshal.GetExceptionForHR(unchecked((int)hr)); } result.AddRange(FltmcManager.MarshalFilterInfo(buffer.DangerousGetPointer())); } } catch (Exception e) { string message = string.Format(CultureInfo.InvariantCulture, "Unable to get the filter driver information: 0x{0:X8}", hr); FltmcManager.Logger.Error(e, message); throw new InvalidOperationException(message, e); } finally { if (filterFindHandle != IntPtr.Zero) { NativeMethods.FilterFindClose(filterFindHandle); } } } } return result; }