628 lines
23 KiB
C#
628 lines
23 KiB
C#
|
//////////////////////////////////////////////////
|
||
|
// Created by Ivan Latunov - IvanWeb.com //
|
||
|
//----------------------------------------------//
|
||
|
// This program is free software. You can //
|
||
|
// redistribute it and/or modify it as you wish //
|
||
|
//////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
using System;
|
||
|
|
||
|
using sscs.communication.win.InterProcessComm;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using System.Text;
|
||
|
|
||
|
using HANDLE = System.IntPtr;
|
||
|
|
||
|
namespace sscs.communication.win.NamedPipes
|
||
|
{
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// A utility class that exposes named pipes operations.
|
||
|
/// </summary>
|
||
|
/// <remarks>
|
||
|
/// This class uses the exposed exposed kernel32.dll methods by the
|
||
|
/// <see cref="AppModule.NamedPipes.NamedPipeNative">NamedPipeNative</see> class
|
||
|
/// to provided controlled named pipe functionality.
|
||
|
/// </remarks>
|
||
|
#endregion
|
||
|
public sealed class NamedPipeWrapper
|
||
|
{
|
||
|
|
||
|
public const int TOKEN_QUERY = 0X00000008;
|
||
|
|
||
|
const int ERROR_NO_MORE_ITEMS = 259;
|
||
|
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// The number of retries when creating a pipe or connecting to a pipe.
|
||
|
/// </summary>
|
||
|
#endregion
|
||
|
private const int ATTEMPTS = 2;
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// Wait time for the
|
||
|
/// <see cref="AppModule.NamedPipes.NamedPipeNative.WaitNamedPipe">NamedPipeNative.WaitNamedPipe</see>
|
||
|
/// operation.
|
||
|
/// </summary>
|
||
|
#endregion
|
||
|
private const int WAIT_TIME = 5000;
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// Reads a string from a named pipe using the UTF8 encoding.
|
||
|
/// </summary>
|
||
|
/// <param name="handle">The pipe handle.</param>
|
||
|
/// <param name="maxBytes">The maximum bytes to read.</param>
|
||
|
/// <returns>A UTF8 string.</returns>
|
||
|
/// <remarks>This function uses
|
||
|
/// <see cref="AppModule.NamedPipes.NamedPipeWrapper.ReadBytes">AppModule.NamedPipes.ReadBytes</see>
|
||
|
/// to read the bytes from the pipe and then converts them to string.<br/><br/>
|
||
|
/// The first four bytes of the pipe data are expected to contain
|
||
|
/// the data length of the message. This method first reads those four
|
||
|
/// bytes and converts them to integer. It then continues to read from the pipe using
|
||
|
/// the extracted data length.
|
||
|
/// </remarks>
|
||
|
#endregion
|
||
|
public static string Read(PipeHandle handle, int maxBytes)
|
||
|
{
|
||
|
string returnVal = "";
|
||
|
byte[] bytes = ReadBytes(handle, maxBytes);
|
||
|
if (bytes != null)
|
||
|
{
|
||
|
returnVal = System.Text.Encoding.UTF8.GetString(bytes);
|
||
|
}
|
||
|
|
||
|
return returnVal;
|
||
|
}
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// Reads the bytes from a named pipe.
|
||
|
/// </summary>
|
||
|
/// <param name="handle">The pipe handle.</param>
|
||
|
/// <param name="maxBytes">The maximum bytes to read.</param>
|
||
|
/// <returns>An array of bytes.</returns>
|
||
|
/// <remarks>This method expects that the first four bytes in the pipe define
|
||
|
/// the length of the data to read. If the data length is greater than
|
||
|
/// <b>maxBytes</b> the method returns null.<br/><br/>
|
||
|
/// The first four bytes of the pipe data are expected to contain
|
||
|
/// the data length of the message. This method first reads those four
|
||
|
/// bytes and converts them to integer. It then continues to read from the pipe using
|
||
|
/// the extracted data length.
|
||
|
/// </remarks>
|
||
|
#endregion
|
||
|
public static byte[] ReadBytes(PipeHandle handle, int maxBytes)
|
||
|
{
|
||
|
byte[] numReadWritten = new byte[4];
|
||
|
byte[] intBytes = new byte[4];
|
||
|
byte[] msgBytes = null;
|
||
|
int len;
|
||
|
|
||
|
// Set the Handle state to Reading
|
||
|
handle.State = InterProcessConnectionState.Reading;
|
||
|
// Read the first four bytes and convert them to integer
|
||
|
bool bReadSuccessful = true;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
bReadSuccessful = NamedPipeNative.ReadFile(handle.Handle, intBytes, 4, numReadWritten, 0);
|
||
|
}
|
||
|
catch (Exception)
|
||
|
{
|
||
|
// Console.WriteLine("Error on ReadFile "+e.ToString());
|
||
|
}
|
||
|
|
||
|
if (bReadSuccessful)
|
||
|
{
|
||
|
len = BitConverter.ToInt32(intBytes, 0);
|
||
|
msgBytes = new byte[len];
|
||
|
// Read the rest of the data
|
||
|
if (!NamedPipeNative.ReadFile(handle.Handle, msgBytes, (uint)len, numReadWritten, 0))
|
||
|
{
|
||
|
handle.State = InterProcessConnectionState.Error;
|
||
|
throw new NamedPipeIOException("Error reading from pipe. Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError());
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
handle.State = InterProcessConnectionState.Error;
|
||
|
throw new NamedPipeIOException("Error reading from pipe. Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError());
|
||
|
}
|
||
|
handle.State = InterProcessConnectionState.ReadData;
|
||
|
if (len > maxBytes)
|
||
|
{
|
||
|
return null;
|
||
|
}
|
||
|
return msgBytes;
|
||
|
}
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// Writes a string to a named pipe.
|
||
|
/// </summary>
|
||
|
/// <param name="handle">The pipe handle.</param>
|
||
|
/// <param name="text">The text to write to the pipe.</param>
|
||
|
/// <remarks>This method converts the text into an array of bytes, using the
|
||
|
/// UTF8 encoding and the uses
|
||
|
/// <see cref="AppModule.NamedPipes.NamedPipeWrapper.WriteBytes">AppModule.NamedPipes.WriteBytes</see>
|
||
|
/// to write to the pipe.<br/><br/>
|
||
|
/// When writing to a pipe the method first writes four bytes that define the data length.
|
||
|
/// It then writes the whole message.</remarks>
|
||
|
#endregion
|
||
|
public static void Write(PipeHandle handle, string text)
|
||
|
{
|
||
|
WriteBytes(handle, System.Text.Encoding.UTF8.GetBytes(text));
|
||
|
}
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// Writes an array of bytes to a named pipe.
|
||
|
/// </summary>
|
||
|
/// <param name="handle">The pipe handle.</param>
|
||
|
/// <param name="bytes">The bytes to write.</param>
|
||
|
/// <remarks>If we try bytes array we attempt to write is empty then this method write a space character to the pipe. This is necessary because the other end of the pipe uses a blocking Read operation so we must write someting.<br/><br/>
|
||
|
/// The bytes length is restricted by the <b>maxBytes</b> parameter, which is done primarily for security reasons.<br/><br/>
|
||
|
/// When writing to a pipe the method first writes four bytes that define the data length.
|
||
|
/// It then writes the whole message.</remarks>
|
||
|
#endregion
|
||
|
public static void WriteBytes(PipeHandle handle, byte[] bytes)
|
||
|
{
|
||
|
byte[] numReadWritten = new byte[4];
|
||
|
uint len;
|
||
|
|
||
|
if (bytes == null)
|
||
|
{
|
||
|
bytes = new byte[0];
|
||
|
}
|
||
|
if (bytes.Length == 0)
|
||
|
{
|
||
|
bytes = new byte[1];
|
||
|
bytes = System.Text.Encoding.UTF8.GetBytes(" ");
|
||
|
}
|
||
|
// Get the message length
|
||
|
len = (uint)bytes.Length;
|
||
|
handle.State = InterProcessConnectionState.Writing;
|
||
|
// Write four bytes that define the message length
|
||
|
if (NamedPipeNative.WriteFile(handle.Handle, BitConverter.GetBytes(len), 4, numReadWritten, 0)) {
|
||
|
// Write the whole message
|
||
|
if (!NamedPipeNative.WriteFile(handle.Handle, bytes, len, numReadWritten, 0)) {
|
||
|
handle.State = InterProcessConnectionState.Error;
|
||
|
throw new NamedPipeIOException("Error writing to pipe. Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError());
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
handle.State = InterProcessConnectionState.Error;
|
||
|
throw new NamedPipeIOException("Error writing to pipe. Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError());
|
||
|
}
|
||
|
handle.State = InterProcessConnectionState.Flushing;
|
||
|
Flush(handle);
|
||
|
handle.State = InterProcessConnectionState.FlushedData;
|
||
|
}
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// Tries to connect to a named pipe on the same machine.
|
||
|
/// </summary>
|
||
|
/// <param name="pipeName">The name of the pipe.</param>
|
||
|
/// <param name="handle">The resulting pipe handle.</param>
|
||
|
/// <returns>Return true if the attempt succeeds.</returns>
|
||
|
/// <remarks>This method is used mainly when stopping the pipe server. It unblocks the existing pipes, which wait for client connection.</remarks>
|
||
|
#endregion
|
||
|
public static bool TryConnectToPipe(string pipeName, out PipeHandle handle)
|
||
|
{
|
||
|
return TryConnectToPipe(pipeName, ".", out handle);
|
||
|
}
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// Tries to connect to a named pipe.
|
||
|
/// </summary>
|
||
|
/// <param name="pipeName">The name of the pipe.</param>
|
||
|
/// <param name="serverName">The name of the server.</param>
|
||
|
/// <param name="handle">The resulting pipe handle.</param>
|
||
|
/// <returns>Return true if the attempt succeeds.</returns>
|
||
|
/// <remarks>This method is used mainly when stopping the pipe server. It unblocks the existing pipes, which wait for client connection.</remarks>
|
||
|
#endregion
|
||
|
public static bool TryConnectToPipe(string pipeName, string serverName, out PipeHandle handle)
|
||
|
{
|
||
|
handle = new PipeHandle();
|
||
|
// Build the pipe name string
|
||
|
string name = @"\\" + serverName + @"\pipe\" + pipeName;
|
||
|
handle.State = InterProcessConnectionState.ConnectingToServer;
|
||
|
// Try to connect to a server pipe
|
||
|
handle.Handle = NamedPipeNative.CreateFile(name, NamedPipeNative.GENERIC_READ | NamedPipeNative.GENERIC_WRITE, 0, null, NamedPipeNative.OPEN_EXISTING, 0, 0);
|
||
|
if (handle.Handle.ToInt32() != NamedPipeNative.INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
handle.State = InterProcessConnectionState.ConnectedToServer;
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
handle.State = InterProcessConnectionState.Error;
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// Connects to a server named pipe on the same machine.
|
||
|
/// </summary>
|
||
|
/// <param name="pipeName">The pipe name.</param>
|
||
|
/// <returns>The pipe handle, which also contains the pipe state.</returns>
|
||
|
/// <remarks>This method is used by clients to establish a pipe connection with a server pipe.</remarks>
|
||
|
#endregion
|
||
|
public static PipeHandle ConnectToPipe(string pipeName)
|
||
|
{
|
||
|
return ConnectToPipe(pipeName, ".");
|
||
|
}
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// Connects to a server named pipe.
|
||
|
/// </summary>
|
||
|
/// <param name="pipeName">The pipe name.</param>
|
||
|
/// <param name="serverName">The server name.</param>
|
||
|
/// <returns>The pipe handle, which also contains the pipe state.</returns>
|
||
|
/// <remarks>This method is used by clients to establish a pipe connection with a server pipe.</remarks>
|
||
|
#endregion
|
||
|
public static PipeHandle ConnectToPipe(string pipeName, string serverName)
|
||
|
{
|
||
|
PipeHandle handle = new PipeHandle();
|
||
|
// Build the name of the pipe.
|
||
|
string name = @"\\" + serverName + @"\PIPE\" + pipeName;
|
||
|
|
||
|
for (int i = 1; i<=ATTEMPTS; i++)
|
||
|
{
|
||
|
handle.State = InterProcessConnectionState.ConnectingToServer;
|
||
|
// Try to connect to the server
|
||
|
handle.Handle = NamedPipeNative.CreateFile(name, NamedPipeNative.GENERIC_READ | NamedPipeNative.GENERIC_WRITE, 0, null, NamedPipeNative.OPEN_EXISTING, 0, 0);
|
||
|
if (handle.Handle.ToInt32() != NamedPipeNative.INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
// The client managed to connect to the server pipe
|
||
|
handle.State = InterProcessConnectionState.ConnectedToServer;
|
||
|
// Set the read mode of the pipe channel
|
||
|
uint mode = NamedPipeNative.PIPE_READMODE_MESSAGE;
|
||
|
if (NamedPipeNative.SetNamedPipeHandleState(handle.Handle, ref mode, IntPtr.Zero, IntPtr.Zero))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
if (i >= ATTEMPTS)
|
||
|
{
|
||
|
handle.State = InterProcessConnectionState.Error;
|
||
|
throw new NamedPipeIOException("Error setting read mode on pipe " + name + " . Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError());
|
||
|
}
|
||
|
}
|
||
|
if (i >= ATTEMPTS)
|
||
|
{
|
||
|
if (NamedPipeNative.GetLastError() != NamedPipeNative.ERROR_PIPE_BUSY)
|
||
|
{
|
||
|
handle.State = InterProcessConnectionState.Error;
|
||
|
// After a certain number of unsuccessful attempt raise an exception
|
||
|
throw new NamedPipeIOException("Error connecting to pipe " + name + " . Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
handle.State = InterProcessConnectionState.Error;
|
||
|
throw new NamedPipeIOException("Pipe " + name + " is too busy. Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError());
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// The pipe is busy so lets wait for some time and try again
|
||
|
if (NamedPipeNative.GetLastError() == NamedPipeNative.ERROR_PIPE_BUSY)
|
||
|
NamedPipeNative.WaitNamedPipe(name, WAIT_TIME);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return handle;
|
||
|
}
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// Creates a server named pipe.
|
||
|
/// </summary>
|
||
|
/// <param name="name">The name of the pipe.</param>
|
||
|
/// <param name="outBuffer">The size of the outbound buffer.</param>
|
||
|
/// <param name="inBuffer">The size of the inbound buffer.</param>
|
||
|
/// <returns>The pipe handle.</returns>
|
||
|
#endregion
|
||
|
public static PipeHandle Create(string name, uint outBuffer, uint inBuffer)
|
||
|
{
|
||
|
if ((name.IndexOf("pipe") < 0) && (name.IndexOf("PIPE") < 0))
|
||
|
name = @"\\.\pipe\" + name;
|
||
|
|
||
|
PipeHandle handle = new PipeHandle();
|
||
|
for (int i = 1; i<=ATTEMPTS; i++)
|
||
|
{
|
||
|
handle.State = InterProcessConnectionState.Creating;
|
||
|
handle.Handle = NamedPipeNative.CreateNamedPipe(
|
||
|
name,
|
||
|
NamedPipeNative.PIPE_ACCESS_DUPLEX,
|
||
|
NamedPipeNative.PIPE_TYPE_MESSAGE | NamedPipeNative.PIPE_READMODE_MESSAGE | NamedPipeNative.PIPE_WAIT,
|
||
|
NamedPipeNative.PIPE_UNLIMITED_INSTANCES,
|
||
|
outBuffer,
|
||
|
inBuffer,
|
||
|
NamedPipeNative.NMPWAIT_WAIT_FOREVER,
|
||
|
IntPtr.Zero);
|
||
|
if (handle.Handle.ToInt32() != NamedPipeNative.INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
handle.State = InterProcessConnectionState.Created;
|
||
|
break;
|
||
|
}
|
||
|
if (i >= ATTEMPTS)
|
||
|
{
|
||
|
handle.State = InterProcessConnectionState.Error;
|
||
|
throw new NamedPipeIOException("Error creating named pipe " + name + " . Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return handle;
|
||
|
}
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// Starts waiting for client connections.
|
||
|
/// </summary>
|
||
|
/// <remarks>
|
||
|
/// Blocks the current execution until a client pipe attempts to establish a connection.
|
||
|
/// </remarks>
|
||
|
/// <param name="handle">The pipe handle.</param>
|
||
|
#endregion
|
||
|
public static void Connect(PipeHandle handle)
|
||
|
{
|
||
|
handle.State = InterProcessConnectionState.WaitingForClient;
|
||
|
bool connected = NamedPipeNative.ConnectNamedPipe(handle.Handle, null);
|
||
|
handle.State = InterProcessConnectionState.ConnectedToClient;
|
||
|
if (!connected && NamedPipeNative.GetLastError() != NamedPipeNative.ERROR_PIPE_CONNECTED)
|
||
|
{
|
||
|
handle.State = InterProcessConnectionState.Error;
|
||
|
throw new NamedPipeIOException("Error connecting pipe. Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError());
|
||
|
}
|
||
|
}
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// Returns the number of instances of a named pipe.
|
||
|
/// </summary>
|
||
|
/// <param name="handle">The pipe handle.</param>
|
||
|
/// <returns>The number of instances.</returns>
|
||
|
#endregion
|
||
|
public static uint NumberPipeInstances(PipeHandle handle)
|
||
|
{
|
||
|
uint curInstances = 0;
|
||
|
|
||
|
if (NamedPipeNative.GetNamedPipeHandleState(handle.Handle, IntPtr.Zero, ref curInstances, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero))
|
||
|
{
|
||
|
return curInstances;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
throw new NamedPipeIOException("Error getting the pipe state. Internal error: " + NamedPipeNative.GetLastError().ToString(), NamedPipeNative.GetLastError());
|
||
|
}
|
||
|
}
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// Closes a named pipe and releases the native handle.
|
||
|
/// </summary>
|
||
|
/// <param name="handle">The pipe handle.</param>
|
||
|
#endregion
|
||
|
public static void Close(PipeHandle handle)
|
||
|
{
|
||
|
handle.State = InterProcessConnectionState.Closing;
|
||
|
NamedPipeNative.CloseHandle(handle.Handle);
|
||
|
handle.Handle = IntPtr.Zero;
|
||
|
handle.State = InterProcessConnectionState.Closed;
|
||
|
}
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// Flushes all the data in a named pipe.
|
||
|
/// </summary>
|
||
|
/// <param name="handle">The pipe handle.</param>
|
||
|
#endregion
|
||
|
public static void Flush(PipeHandle handle)
|
||
|
{
|
||
|
handle.State = InterProcessConnectionState.Flushing;
|
||
|
NamedPipeNative.FlushFileBuffers(handle.Handle);
|
||
|
handle.State = InterProcessConnectionState.FlushedData;
|
||
|
}
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// Disconnects a server named pipe from the client.
|
||
|
/// </summary>
|
||
|
/// <remarks>
|
||
|
/// Server pipes can be reused by first disconnecting them from the client and then
|
||
|
/// calling the <see cref="AppModule.NamedPipes.NamedPipeWrapper.Connect">Connect</see>
|
||
|
/// method to start listening. This improves the performance as it is not necessary
|
||
|
/// to create new pipe handles.
|
||
|
/// </remarks>
|
||
|
/// <param name="handle">The pipe handle.</param>
|
||
|
#endregion
|
||
|
public static void Disconnect(PipeHandle handle)
|
||
|
{
|
||
|
handle.State = InterProcessConnectionState.Disconnecting;
|
||
|
NamedPipeNative.DisconnectNamedPipe(handle.Handle);
|
||
|
handle.State = InterProcessConnectionState.Disconnected;
|
||
|
}
|
||
|
#region Comments
|
||
|
/// <summary>
|
||
|
/// Private constructor.
|
||
|
/// </summary>
|
||
|
#endregion
|
||
|
private NamedPipeWrapper() {}
|
||
|
|
||
|
|
||
|
// Client USERID stuff
|
||
|
// 1. call ImpersonateNamedPipeClient(hPipe)
|
||
|
// 2. call OpenThreadToken(GetCurrentThread(),
|
||
|
// TOKEN_QUERY | TOKEN_QUERY_SOURCE,
|
||
|
// FALSE,
|
||
|
// phUserToken);
|
||
|
|
||
|
public static int ImpersonateNamePipeClient(IntPtr hPipeHandle)
|
||
|
{
|
||
|
int rcode = NamedPipeNative.ImpersonateNamedPipeClient(hPipeHandle);
|
||
|
return rcode;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int PerformDump(HANDLE token)
|
||
|
{
|
||
|
StringBuilder sb = new StringBuilder();
|
||
|
NamedPipeNative.TOKEN_USER tokUser;
|
||
|
const int bufLength = 256;
|
||
|
IntPtr tu = Marshal.AllocHGlobal( bufLength );
|
||
|
int cb = bufLength;
|
||
|
if (NamedPipeNative.GetTokenInformation( token, NamedPipeNative.TOKEN_INFORMATION_CLASS.TokenUser, tu, cb, ref cb ))
|
||
|
Console.WriteLine("GetTokenInformation successful");
|
||
|
else
|
||
|
{
|
||
|
Console.WriteLine("GetTokenInformation NOT successful");
|
||
|
uint error = NamedPipeNative.GetLastError();
|
||
|
Console.WriteLine("error" + error.ToString());
|
||
|
}
|
||
|
|
||
|
tokUser = (NamedPipeNative.TOKEN_USER) Marshal.PtrToStructure(tu, typeof(NamedPipeNative.TOKEN_USER) );
|
||
|
//sb.Append(DumpAccountSid(tokUser.User.Sid));
|
||
|
IntPtr pUserID = tokUser.User.Sid;
|
||
|
//Console.WriteLine("UserID: " + pUserID);
|
||
|
|
||
|
DumpAccountSid(pUserID);
|
||
|
Marshal.FreeHGlobal( tu );
|
||
|
|
||
|
|
||
|
tu = Marshal.AllocHGlobal(bufLength);
|
||
|
cb = bufLength;
|
||
|
|
||
|
// get token states
|
||
|
NamedPipeNative.TOKEN_STATISTICS stats;
|
||
|
|
||
|
if (NamedPipeNative.GetTokenInformation(token, NamedPipeNative.TOKEN_INFORMATION_CLASS.TokenStatistics, tu, cb, ref cb))
|
||
|
{
|
||
|
stats = (NamedPipeNative.TOKEN_STATISTICS) Marshal.PtrToStructure(tu, typeof(NamedPipeNative.TOKEN_STATISTICS));
|
||
|
Console.WriteLine("UserLow: "+stats.AuthenticationId.LowPart.ToString());
|
||
|
Console.WriteLine("UserHigh: "+stats.AuthenticationId.HighPart.ToString());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Console.WriteLine("failed");
|
||
|
}
|
||
|
|
||
|
return (int)pUserID;
|
||
|
}
|
||
|
|
||
|
|
||
|
static string DumpAccountSid(IntPtr SID)
|
||
|
{
|
||
|
int cchAccount = 0;
|
||
|
int cchDomain = 0;
|
||
|
int snu = 0 ;
|
||
|
StringBuilder sb = new StringBuilder();
|
||
|
|
||
|
// Caller allocated buffer
|
||
|
StringBuilder Account= null;
|
||
|
StringBuilder Domain = null;
|
||
|
bool ret = NamedPipeNative.LookupAccountSid(null, SID, Account, ref cchAccount, Domain, ref cchDomain, ref snu);
|
||
|
if ( ret == true )
|
||
|
if ( Marshal.GetLastWin32Error() == ERROR_NO_MORE_ITEMS )
|
||
|
return "Error";
|
||
|
try
|
||
|
{
|
||
|
Account = new StringBuilder( cchAccount );
|
||
|
Domain = new StringBuilder( cchDomain );
|
||
|
ret = NamedPipeNative.LookupAccountSid(null, SID, Account, ref cchAccount, Domain, ref cchDomain, ref snu);
|
||
|
if (ret)
|
||
|
{
|
||
|
sb.Append(Domain);
|
||
|
sb.Append(@"\\");
|
||
|
sb.Append(Account);
|
||
|
}
|
||
|
else
|
||
|
Console.WriteLine("logon account (no name) ");
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
Console.WriteLine(ex.Message);
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
}
|
||
|
string SidString = null;
|
||
|
NamedPipeNative.ConvertSidToStringSid(SID, ref SidString);
|
||
|
sb.Append("\nSID: ");
|
||
|
sb.Append(SidString);
|
||
|
|
||
|
|
||
|
Console.WriteLine("Acct info: "+ sb.ToString());
|
||
|
return sb.ToString();
|
||
|
}
|
||
|
|
||
|
public static int GetLocalUserID(PipeHandle handle, ref int lowPart, ref int highPart, ref string SidString)
|
||
|
{
|
||
|
int rcode = -1;
|
||
|
// get client userID
|
||
|
int code = NamedPipeNative.ImpersonateNamedPipeClient(handle.Handle);
|
||
|
if (code == 0)
|
||
|
{
|
||
|
uint lastError = NamedPipeNative.GetLastError();
|
||
|
Console.WriteLine("ImpersonateNamedPipeClient Error: "+rcode.ToString());
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
try
|
||
|
{
|
||
|
IntPtr hThread = NamedPipeNative.GetCurrentThread();
|
||
|
uint iDesiredInfo = 24; //TOKEN_QUERY | TOKEN_QUERY_SOURCE;
|
||
|
IntPtr userToken = Marshal.AllocHGlobal(4);
|
||
|
|
||
|
if (NamedPipeNative.OpenThreadToken(hThread, iDesiredInfo, true, out userToken))
|
||
|
{
|
||
|
|
||
|
StringBuilder sb = new StringBuilder();
|
||
|
NamedPipeNative.TOKEN_USER tokUser;
|
||
|
const int bufLength = 256;
|
||
|
IntPtr tu = Marshal.AllocHGlobal( bufLength );
|
||
|
int cb = bufLength;
|
||
|
if (NamedPipeNative.GetTokenInformation( userToken, NamedPipeNative.TOKEN_INFORMATION_CLASS.TokenUser, tu, cb, ref cb ))
|
||
|
{
|
||
|
tokUser = (NamedPipeNative.TOKEN_USER) Marshal.PtrToStructure(tu, typeof(NamedPipeNative.TOKEN_USER) );
|
||
|
IntPtr pUserID = tokUser.User.Sid;
|
||
|
Marshal.FreeHGlobal( tu );
|
||
|
|
||
|
// get SID
|
||
|
//string SidString = null;
|
||
|
NamedPipeNative.ConvertSidToStringSid(pUserID, ref SidString);
|
||
|
|
||
|
// get token states
|
||
|
tu = Marshal.AllocHGlobal(bufLength);
|
||
|
cb = bufLength;
|
||
|
NamedPipeNative.TOKEN_STATISTICS stats;
|
||
|
if (NamedPipeNative.GetTokenInformation(userToken, NamedPipeNative.TOKEN_INFORMATION_CLASS.TokenStatistics, tu, cb, ref cb))
|
||
|
{
|
||
|
stats = (NamedPipeNative.TOKEN_STATISTICS) Marshal.PtrToStructure(tu, typeof(NamedPipeNative.TOKEN_STATISTICS));
|
||
|
// copy low and high part
|
||
|
lowPart = stats.AuthenticationId.LowPart;
|
||
|
highPart = stats.AuthenticationId.HighPart;
|
||
|
rcode = -1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Console.WriteLine("GetTokenInformation NOT successful");
|
||
|
uint error = NamedPipeNative.GetLastError();
|
||
|
Console.WriteLine("error" + error.ToString());
|
||
|
}
|
||
|
|
||
|
// close handle
|
||
|
NamedPipeNative.CloseHandle(hThread);
|
||
|
NamedPipeNative.RevertToSelf();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int lastError = Marshal.GetLastWin32Error();
|
||
|
uint errorcode = NamedPipeNative.GetLastError();
|
||
|
Console.WriteLine("OpenThreadToken Error: "+ errorcode.ToString() + " code2: "+rcode.ToString());
|
||
|
}
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
int error = Marshal.GetLastWin32Error();
|
||
|
Console.WriteLine(ex.ToString());
|
||
|
return rcode;
|
||
|
}
|
||
|
// end
|
||
|
|
||
|
return rcode;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|