Updated comments.
This commit is contained in:
@@ -7,16 +7,31 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads and writes value types to byte arrays with explicit endianness.
|
||||
/// </summary>
|
||||
public static class ByteWriter
|
||||
{
|
||||
// Big endian: Most significant byte at lowest address in memory.
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 2-byte signed integer to the buffer in big-endian format.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write to the buffer.</param>
|
||||
/// <param name="buffer">The buffer to write to.</param>
|
||||
/// <param name="position">The index of the first byte to write to.</param>
|
||||
public static void WriteInt16_BE( Int16 value, byte[] buffer, int position )
|
||||
{
|
||||
buffer[position + 0] = (byte)( value >> 8 );
|
||||
buffer[position + 1] = (byte)( value );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 4-byte signed integer to the buffer in big-endian format.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write to the buffer.</param>
|
||||
/// <param name="buffer">The buffer to write to.</param>
|
||||
/// <param name="position">The index of the first byte to write to.</param>
|
||||
public static void WriteInt32_BE( Int32 value, byte[] buffer, int position )
|
||||
{
|
||||
buffer[position + 0] = (byte)( value >> 24 );
|
||||
@@ -26,6 +41,13 @@ namespace NSspi
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 2-byte signed integer that is stored in the buffer in big-endian format.
|
||||
/// The returned value is in the native endianness.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to read.</param>
|
||||
/// <param name="position">The index of the first byte to read.</param>
|
||||
/// <returns></returns>
|
||||
public static Int16 ReadInt16_BE( byte[] buffer, int position )
|
||||
{
|
||||
Int16 value;
|
||||
@@ -36,6 +58,13 @@ namespace NSspi
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte signed integer that is stored in the buffer in big-endian format.
|
||||
/// The returned value is in the native endianness.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to read.</param>
|
||||
/// <param name="position">The index of the first byte to read.</param>
|
||||
/// <returns></returns>
|
||||
public static Int32 ReadInt32_BE( byte[] buffer, int position )
|
||||
{
|
||||
Int32 value;
|
||||
@@ -47,6 +76,5 @@ namespace NSspi
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace NSspi.Credentials.Credentials
|
||||
internal struct QueryNameAttribCarrier
|
||||
{
|
||||
/// <summary>
|
||||
/// A pointer to a null-terminated ascii c-string containing the principle name
|
||||
/// A pointer to a null-terminated ascii-encoded containing the principle name
|
||||
/// associated with a credential
|
||||
/// </summary>
|
||||
public IntPtr Name;
|
||||
|
||||
@@ -12,6 +12,11 @@ namespace NSspi.Credentials
|
||||
/// </summary>
|
||||
public class ServerCredential : CurrentCredential
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ServerCredential class, acquiring credentials from
|
||||
/// the current thread's security context.
|
||||
/// </summary>
|
||||
/// <param name="package">The name of the security package to obtain credentials from.</param>
|
||||
public ServerCredential( string package )
|
||||
: base( package, CredentialUse.Inbound )
|
||||
{
|
||||
|
||||
@@ -11,20 +11,6 @@ namespace NSspi
|
||||
{
|
||||
internal static class NativeMethods
|
||||
{
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa374713(v=vs.85).aspx
|
||||
|
||||
// The REMSSPI sample:
|
||||
|
||||
// A C++ pure client/server example:
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa380536(v=vs.85).aspx
|
||||
|
||||
|
||||
/*
|
||||
SECURITY_STATUS SEC_Entry FreeContextBuffer(
|
||||
_In_ PVOID pvContextBuffer
|
||||
);
|
||||
*/
|
||||
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success)]
|
||||
[DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus FreeContextBuffer( IntPtr buffer );
|
||||
|
||||
@@ -6,12 +6,24 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides canonical names for security pacakges.
|
||||
/// </summary>
|
||||
public static class PackageNames
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the Negotiate security package.
|
||||
/// </summary>
|
||||
public const string Negotiate = "Negotiate";
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the Kerberos security package.
|
||||
/// </summary>
|
||||
public const string Kerberos = "Kerberos";
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the NTLM security package.
|
||||
/// </summary>
|
||||
public const string Ntlm = "NTLM";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,16 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi
|
||||
{
|
||||
/// <summary>
|
||||
/// Queries information about security packages.
|
||||
/// </summary>
|
||||
public static class PackageSupport
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the properties of the named package.
|
||||
/// </summary>
|
||||
/// <param name="packageName">The name of the package.</param>
|
||||
/// <returns></returns>
|
||||
public static SecPkgInfo GetPackageCapabilities( string packageName )
|
||||
{
|
||||
SecPkgInfo info;
|
||||
@@ -52,6 +60,10 @@ namespace NSspi
|
||||
return info;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all known security package providers and their properties.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static SecPkgInfo[] EnumeratePackages()
|
||||
{
|
||||
SecurityStatus status = SecurityStatus.InternalError;
|
||||
|
||||
@@ -7,19 +7,51 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Buffers
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a native SecureBuffer structure, which is used for communicating
|
||||
/// buffers to the native APIs.
|
||||
/// </summary>
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
internal struct SecureBufferInternal
|
||||
{
|
||||
/// <summary>
|
||||
/// When provided to the native API, the total number of bytes available in the buffer.
|
||||
/// On return from the native API, the number of bytes that were filled or used by the
|
||||
/// native API.
|
||||
/// </summary>
|
||||
public int Count;
|
||||
|
||||
/// <summary>
|
||||
/// The type or purpose of the buffer.
|
||||
/// </summary>
|
||||
public BufferType Type;
|
||||
|
||||
// A pointer to a byte[]
|
||||
/// <summary>
|
||||
/// An pointer to a pinned byte[] buffer.
|
||||
/// </summary>
|
||||
public IntPtr Buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores buffers to provide tokens and data to the native SSPI APIs.
|
||||
/// </summary>
|
||||
/// <remarks>The buffer is translated into a SecureBufferInternal for the actual call.
|
||||
/// To keep the call setup code simple, and to centralize the buffer pinning code,
|
||||
/// this class stores and returns buffers as regular byte arrays. The buffer
|
||||
/// pinning support code in SecureBufferAdapter handles conversion to SecureBufferInternal
|
||||
/// for pass to the managed api, as well as pinning relevant chunks of memory.
|
||||
///
|
||||
/// Furthermore, the native API may not use the entire buffer, and so a mechanism
|
||||
/// is needed to communicate the usage of the buffer separate from the length
|
||||
/// of the buffer.</remarks>
|
||||
internal class SecureBuffer
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SecureBuffer class.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to wrap.</param>
|
||||
/// <param name="type">The type or purpose of the buffer, for purposes of
|
||||
/// invoking the native API.</param>
|
||||
public SecureBuffer( byte[] buffer, BufferType type )
|
||||
{
|
||||
this.Buffer = buffer;
|
||||
@@ -27,10 +59,20 @@ namespace NSspi.Buffers
|
||||
this.Length = this.Buffer.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The type or purposes of the API, for invoking the native API.
|
||||
/// </summary>
|
||||
public BufferType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The buffer to provide to the native API.
|
||||
/// </summary>
|
||||
public byte[] Buffer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of elements that were actually filled or used by the native API,
|
||||
/// which may be less than the total length of the buffer.
|
||||
/// </summary>
|
||||
public int Length { get; internal set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,26 +8,109 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Buffers
|
||||
{
|
||||
/// <summary>
|
||||
/// Prepares SecureBuffers for providing them to native API calls.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The native APIs consume lists of buffers, with each buffer indicating its type or purpose.
|
||||
///
|
||||
/// The buffers themselves are simple byte arrays, and the native APIs consume arrays of buffers.
|
||||
///
|
||||
/// Since winapi calling convention, perhaps as an extension of C calling convention, does not
|
||||
/// provide a standard convention means of communicating the length of any array, custom structures
|
||||
/// must be created to carry the buffer length and usage.
|
||||
///
|
||||
/// Not only does the API need to know how long each buffer is, and how long the array of buffers is,
|
||||
/// it needs to communicate back how much of each buffer was filled; we may provide it a token buffer
|
||||
/// that is 12288 bytes long, but it might only use 125 bytes of that, which we need a way of knowing.
|
||||
///
|
||||
/// As a result of this, the API requires byte arrays to be carried in structs that are natively known as
|
||||
/// SecureBuffers (known as SecureBufferInternal in this project), and then arrays of SecureBuffers are
|
||||
/// carried in a SecureBufferDescriptor structure.
|
||||
///
|
||||
/// As such, this class has to do a significant amount of marshaling work just to get the buffers back and
|
||||
/// forth to the native APIs.
|
||||
/// * We have to pin all buffers
|
||||
/// * We have to pin the array of buffers
|
||||
/// * We have to obtain IntPtr handles to each of the buffers and to the array of buffers.
|
||||
/// * Since we provide EasyToUse SecureBuffer classes from the rest of the project, but we
|
||||
/// provide SecureBufferInternal structures from the native API, we have to copy back values
|
||||
/// from the SecureBufferInternal structs to our SecureBuffer class.
|
||||
///
|
||||
/// To make this class easy to use, it accepts either one or many buffers as its constructor; and
|
||||
/// implements IDisposable to know when to marshal values back from the unmanaged structures and to
|
||||
/// release pinned handles.
|
||||
///
|
||||
/// Additionally, in case the adapter is leaked without disposing, the adapter implements a Critical
|
||||
/// Finalizer, to ensure that the GCHandles are released, else we will permanently pin handles.
|
||||
///
|
||||
/// The typical flow is to take one or many buffers; create and fill the neccessary unmanaged structures;
|
||||
/// pin memory; acquire the IntPtr handles; let the caller access the top-level IntPtr representing
|
||||
/// the SecureBufferDescriptor, to provide to the native APIs; wait for the caller to invoke the native
|
||||
/// API; wait for the caller to invoke our Dispose; marshal back any data from the native structures
|
||||
/// (buffer write counts); release all GCHandles to unpin memory.
|
||||
///
|
||||
/// The total descriptor structure is as follows:
|
||||
/// |-- Descriptor handle
|
||||
/// |-- Array of buffers
|
||||
/// |-- Buffer 1
|
||||
/// |-- Buffer 2
|
||||
/// ...
|
||||
/// |-- Buffer N.
|
||||
///
|
||||
/// Each object in that structure must be pinned and passed as an IntPtr to the native APIs.
|
||||
/// All this to pass what boils down to a List of byte arrays..
|
||||
/// </remarks>
|
||||
internal sealed class SecureBufferAdapter : CriticalFinalizerObject, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the adapter has already been disposed.
|
||||
/// </summary>
|
||||
private bool disposed;
|
||||
|
||||
/// <summary>
|
||||
/// The list of mananged SecureBuffers the caller provided to us.
|
||||
/// </summary>
|
||||
private IList<SecureBuffer> buffers;
|
||||
|
||||
/// <summary>
|
||||
/// The top level handle representing the entire descriptor.
|
||||
/// </summary>
|
||||
private GCHandle descriptorHandle;
|
||||
|
||||
private GCHandle[] bufferHandles;
|
||||
|
||||
private SecureBufferDescInternal descriptor;
|
||||
private SecureBufferInternal[] bufferCarrier;
|
||||
/// <summary>
|
||||
/// The handle representing the array of buffers.
|
||||
/// </summary>
|
||||
private GCHandle bufferCarrierHandle;
|
||||
|
||||
/// <summary>
|
||||
/// The handles representing each actual buffer.
|
||||
/// </summary>
|
||||
private GCHandle[] bufferHandles;
|
||||
|
||||
/// <summary>
|
||||
/// The native buffer descriptor
|
||||
/// </summary>
|
||||
private SecureBufferDescInternal descriptor;
|
||||
|
||||
/// <summary>
|
||||
/// An array of the native buffers.
|
||||
/// </summary>
|
||||
private SecureBufferInternal[] bufferCarrier;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a SecureBufferAdapter to carry a single buffer to the native api.
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
public SecureBufferAdapter( SecureBuffer buffer )
|
||||
: this( new[] { buffer } )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the SecureBufferAdapter to carry a list of buffers to the native api.
|
||||
/// </summary>
|
||||
/// <param name="buffers"></param>
|
||||
public SecureBufferAdapter( IList<SecureBuffer> buffers ) : base()
|
||||
{
|
||||
this.buffers = buffers;
|
||||
@@ -66,6 +149,9 @@ namespace NSspi.Buffers
|
||||
Dispose( false );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the top-level pointer to the secure buffer descriptor to pass to the native API.
|
||||
/// </summary>
|
||||
public IntPtr Handle
|
||||
{
|
||||
get
|
||||
@@ -79,12 +165,22 @@ namespace NSspi.Buffers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Completes any buffer passing marshaling and releases all resources associated with the adapter.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose( true );
|
||||
GC.SuppressFinalize( this );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Completes any buffer passing marshaling and releases all resources associated with the adapter.
|
||||
/// This may be called by the finalizer, or by the regular Dispose method. In the case of the finalizer,
|
||||
/// we've been leaked and there's no point in attempting to marshal back data from the native structures,
|
||||
/// nor should we anyway since they may be gone.
|
||||
/// </summary>
|
||||
/// <param name="disposing">Whether Dispose is being called.</param>
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
private void Dispose( bool disposing )
|
||||
{
|
||||
@@ -121,6 +217,5 @@ namespace NSspi.Buffers
|
||||
|
||||
this.disposed = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,20 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Buffers
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes how a buffer's opaque internals should be stored, with regards to byte ordering.
|
||||
/// </summary>
|
||||
internal enum SecureBufferDataRep : int
|
||||
{
|
||||
/*
|
||||
#define SECURITY_NATIVE_DREP 0x00000010
|
||||
#define SECURITY_NETWORK_DREP 0x00000000
|
||||
*/
|
||||
Nativee = 0x10,
|
||||
/// <summary>
|
||||
/// Buffers internals are to be stored in the machine native byte order, which will change depending on
|
||||
/// what machine generated the buffer.
|
||||
/// </summary>
|
||||
Native = 0x10,
|
||||
|
||||
/// <summary>
|
||||
/// Buffers are stored in network byte ordering, that is, big endian format.
|
||||
/// </summary>
|
||||
Network = 0x00
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,15 +8,31 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Buffers
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the native layout of the secure buffer descriptor that is provided directly
|
||||
/// to native API calls.
|
||||
/// </summary>
|
||||
[StructLayout( LayoutKind.Sequential)]
|
||||
internal struct SecureBufferDescInternal
|
||||
{
|
||||
/// <summary>
|
||||
/// The buffer structure version.
|
||||
/// </summary>
|
||||
public int Version;
|
||||
|
||||
/// <summary>
|
||||
/// The number of buffers represented by this descriptor.
|
||||
/// </summary>
|
||||
public int NumBuffers;
|
||||
|
||||
// A pointer to a SecureBuffer[]
|
||||
/// <summary>
|
||||
/// A pointer to a array of buffers, where each buffer is a byte[].
|
||||
/// </summary>
|
||||
public IntPtr Buffers;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the buffer structure version supported by this structure. Always 0.
|
||||
/// </summary>
|
||||
public const int ApiVersion = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,16 +6,53 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Buffers
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes the type and purpose of a secure buffer passed to the native API.
|
||||
/// </summary>
|
||||
internal enum BufferType : int
|
||||
{
|
||||
/// <summary>
|
||||
/// The buffer is empty.
|
||||
/// </summary>
|
||||
Empty = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer contains message data. Message data can be plaintext or cipher text data.
|
||||
/// </summary>
|
||||
Data = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer contains opaque authentication token data.
|
||||
/// </summary>
|
||||
Token = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer contains parameters specific to the security package.
|
||||
/// </summary>
|
||||
Parameters = 0x03,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer placeholder indicating that some data is missing.
|
||||
/// </summary>
|
||||
Missing = 0x04,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer passed to an API call contained more data than was necessary for completing the action,
|
||||
/// such as the case when a streaming-mode connection that does not preserve message bounders, such as TCP
|
||||
/// is used as the transport. The extra data is returned back to the caller in a buffer of this type.
|
||||
/// </summary>
|
||||
Extra = 0x05,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer contains a security data trailer, such as a message signature or marker, or framing data.
|
||||
/// </summary>
|
||||
Trailer = 0x06,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer contains a security data header, such as a message signature, marker, or framing data.
|
||||
/// </summary>
|
||||
Header = 0x07,
|
||||
|
||||
Padding = 0x09,
|
||||
Stream = 0x0A,
|
||||
ChannelBindings = 0x0E,
|
||||
|
||||
@@ -60,7 +60,12 @@ namespace NSspi
|
||||
Unsupported = 0x80090302,
|
||||
TargetUnknown = 0x80090303,
|
||||
InternalError = 0x80090304,
|
||||
|
||||
/// <summary>
|
||||
/// No security provider package was found with the given name.
|
||||
/// </summary>
|
||||
PackageNotFound = 0x80090305,
|
||||
|
||||
NotOwner = 0x80090306,
|
||||
CannotInstall = 0x80090307,
|
||||
InvalidToken = 0x80090308,
|
||||
@@ -73,6 +78,18 @@ namespace NSspi
|
||||
MessageAltered = 0x8009030F,
|
||||
OutOfSequence = 0x80090310,
|
||||
NoAuthenticatingAuthority = 0x80090311,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer provided to an SSPI API call contained a message that was not complete.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This occurs regularly with SSPI contexts that exchange data using a streaming context,
|
||||
/// where the data returned from the streaming communications channel, such as a TCP socket,
|
||||
/// did not contain the complete message.
|
||||
/// Similarly, a streaming channel may return too much data, in which case the API function
|
||||
/// will indicate success, but will save off the extra, unrelated data in a buffer of
|
||||
/// type 'extra'.
|
||||
/// </remarks>
|
||||
IncompleteMessage = 0x80090318,
|
||||
IncompleteCredentials = 0x80090320,
|
||||
BufferNotEnough = 0x80090321,
|
||||
@@ -89,8 +106,16 @@ namespace NSspi
|
||||
BadBinding = 0x80090346
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for the SecurityStatus enumeration.
|
||||
/// </summary>
|
||||
public static class SecurityStatusExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns whether or not the status represents an error.
|
||||
/// </summary>
|
||||
/// <param name="status"></param>
|
||||
/// <returns>True if the status represents an error condition.</returns>
|
||||
public static bool IsError( this SecurityStatus status )
|
||||
{
|
||||
return (uint)status > 0x80000000u;
|
||||
|
||||
@@ -11,8 +11,9 @@ using NSspi.Contexts;
|
||||
namespace NSspi
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents any SSPI handle created for credential handles, context handles, and security package
|
||||
/// handles. Any SSPI handle is always the size of two native pointers.
|
||||
/// Represents the raw structure for any handle created for the SSPI API, for example, credential
|
||||
/// handles, context handles, and security package handles. Any SSPI handle is always the size
|
||||
/// of two native pointers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The documentation for SSPI handles can be found here:
|
||||
@@ -21,8 +22,8 @@ namespace NSspi
|
||||
/// This class is not reference safe - if used directly, or referenced directly, it may be leaked,
|
||||
/// or subject to finalizer races, or any of the hundred of things SafeHandles were designed to fix.
|
||||
/// Do not directly use this class - use only though SafeHandle wrapper objects. Any reference needed
|
||||
/// to this handle for performing work (InitializeSecurityContext, eg), should be done through
|
||||
/// a second class SafeSspiHandleReference so that reference counting is properly executed.
|
||||
/// to this handle for performing work (InitializeSecurityContext, eg) should be performed a CER
|
||||
/// that employs handle reference counting across the native API invocation.
|
||||
/// </remarks>
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 1 ) ]
|
||||
internal struct RawSspiHandle
|
||||
@@ -30,12 +31,21 @@ namespace NSspi
|
||||
private IntPtr lowPart;
|
||||
private IntPtr highPart;
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether or not the handle is set to the default, empty value.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsZero()
|
||||
{
|
||||
return this.lowPart == IntPtr.Zero && this.highPart == IntPtr.Zero;
|
||||
}
|
||||
|
||||
// This guy has to be executed in a CER.
|
||||
/// <summary>
|
||||
/// Sets the handle to an invalid value.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method is executed in a CER during handle release.
|
||||
/// </remarks>
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success)]
|
||||
public void SetInvalid()
|
||||
{
|
||||
@@ -44,7 +54,9 @@ namespace NSspi
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Safely encapsulates a raw handle used in the SSPI api.
|
||||
/// </summary>
|
||||
public abstract class SafeSspiHandle : SafeHandle
|
||||
{
|
||||
internal RawSspiHandle rawHandle;
|
||||
|
||||
@@ -7,19 +7,33 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a Windows API Timestamp structure, which stores time in units of 100 nanosecond
|
||||
/// ticks, counting from January 1st, year 1601 at 00:00 UTC. Time is stored as a 64-bit value.
|
||||
/// </summary>
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
public struct TimeStamp
|
||||
{
|
||||
public static readonly DateTime Epoch = new DateTime( 1601, 1, 1, 0, 0, 0, DateTimeKind.Utc );
|
||||
|
||||
/// <summary>
|
||||
/// Stores the time value. Infinite times are often represented as values near, but not exactly
|
||||
/// at the maximum signed 64-bit 2's complement value.
|
||||
/// </summary>
|
||||
private long time;
|
||||
|
||||
/// <summary>
|
||||
/// Converts the TimeStamp to an equivalant DateTime object. If the TimeStamp represents
|
||||
/// a value larger than DateTime.MaxValue, then DateTime.MaxValue is returned.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public DateTime ToDateTime()
|
||||
{
|
||||
ulong test = (ulong)this.time + (ulong)(Epoch.Ticks);
|
||||
|
||||
// Sometimes the value returned is massive, eg, 0x7fffff154e84ffff, which is a value
|
||||
// somewhere in the year 30848. This would overflow DateTime, since it peaks at 31-Dec-9999.
|
||||
// It turns out that this value corresponds to a TimeStamp's maximum value, reduced by my local timezone
|
||||
// http://stackoverflow.com/questions/24478056/
|
||||
if ( test > (ulong)DateTime.MaxValue.Ticks )
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user