2017-11-27 13:11:20 -05:00
using System ;
2019-04-10 14:13:59 -04:00
using System.Collections ;
using System.Collections.Generic ;
2019-08-15 03:20:08 -04:00
using System.Diagnostics ;
2019-04-10 15:10:35 -04:00
using System.Linq ;
2017-11-27 13:11:20 -05:00
using System.Runtime.InteropServices ;
2020-01-01 17:41:44 -05:00
using System.Security.Principal ;
2019-04-10 14:13:59 -04:00
using Vanara.Extensions ;
2017-11-27 13:11:20 -05:00
using Vanara.InteropServices ;
2018-11-19 23:18:50 -05:00
using static Vanara . PInvoke . Kernel32 ;
2017-11-27 13:11:20 -05:00
namespace Vanara.PInvoke
{
public static partial class AdvApi32
{
/// <summary>Class representation of the native SID structure.</summary>
/// <seealso cref="SafeHGlobalHandle"/>
2019-08-15 03:20:08 -04:00
[DebuggerDisplay("{DebugString}")]
2019-08-09 16:18:18 -04:00
public class SafePSID : SafeMemoryHandle < LocalMemoryMethods > , IEquatable < SafePSID > , IEquatable < PSID > , IEquatable < IntPtr > , ICloneable , ISecurityObject
2017-11-27 13:11:20 -05:00
{
/// <summary>Equivalent to a NULL pointer to a SID.</summary>
2018-11-19 23:18:50 -05:00
public static readonly SafePSID Null = new SafePSID ( 0 ) ;
2017-11-27 13:11:20 -05:00
2018-11-19 23:18:50 -05:00
/// <summary>Initializes a new instance of the <see cref="SafePSID"/> class.</summary>
/// <param name="psid">The existing <see cref="SafePSID"/> instance to duplicate.</param>
2019-08-09 16:18:18 -04:00
public SafePSID ( PSID psid ) : base ( psid . IsNull ? 0 : GetLengthSid ( psid ) ) { if ( ! psid . IsNull ) CopySid ( Size , handle , psid ) ; }
2017-11-27 13:11:20 -05:00
2018-11-19 23:18:50 -05:00
/// <summary>Initializes a new instance of the <see cref="SafePSID"/> class.</summary>
2017-11-27 13:11:20 -05:00
/// <param name="size">The size of memory to allocate, in bytes.</param>
2019-08-15 18:36:12 -04:00
public SafePSID ( SizeT size ) : base ( size )
2017-11-27 13:11:20 -05:00
{
}
2018-11-19 23:18:50 -05:00
/// <summary>Initializes a new instance of the <see cref="SafePSID"/> class.</summary>
2017-11-27 13:11:20 -05:00
/// <param name="sidBytes">An array of bytes that contain a valid Sid.</param>
2018-11-19 23:18:50 -05:00
public SafePSID ( byte [ ] sidBytes ) : base ( sidBytes ? . Length ? ? 0 ) = > Marshal . Copy ( sidBytes , 0 , handle , Size ) ;
2017-11-27 13:11:20 -05:00
2018-11-19 23:18:50 -05:00
/// <summary>Initializes a new instance of the <see cref="SafePSID"/> class.</summary>
2017-11-27 13:11:20 -05:00
/// <param name="sidValue">The string SID value.</param>
2018-11-19 23:18:50 -05:00
public SafePSID ( string sidValue ) : this ( ConvertStringSidToSid ( sidValue ) )
2017-11-27 13:11:20 -05:00
{
}
2019-06-25 19:11:42 -04:00
/// <summary>
/// Initializes a new instance of the <see cref="SafePSID"/> class from a
/// <see cref="System.Security.Principal.SecurityIdentifier"/> instance.
/// </summary>
/// <param name="si">The <see cref="System.Security.Principal.SecurityIdentifier"/> instance.</param>
2019-08-09 16:18:18 -04:00
public SafePSID ( System . Security . Principal . SecurityIdentifier si ) : this ( si is null ? null : GetBytes ( si ) )
2019-06-25 19:11:42 -04:00
{
}
2019-08-09 16:18:18 -04:00
/// <summary>Initializes a new instance of the <see cref="SafePSID"/> class.</summary>
private SafePSID ( ) : base ( ) { }
2021-10-07 17:22:32 -04:00
/// <summary>Gets a pointer to the SID_IDENTIFIER_AUTHORITY structure in this security identifier (SID).</summary>
/// <returns>A pointer to the SID_IDENTIFIER_AUTHORITY structure for this SID structure.</returns>
public PSID_IDENTIFIER_AUTHORITY Authority = > GetSidIdentifierAuthority ( this ) ;
2019-06-25 19:11:42 -04:00
/// <summary>Gets the SID for the current user</summary>
/// <value>The current user's SID.</value>
2020-01-01 17:41:44 -05:00
public static SafePSID Current
{
get
{
using var identity = WindowsIdentity . GetCurrent ( ) ;
return new SafePSID ( identity . User ) ;
}
}
2019-06-25 19:11:42 -04:00
2019-08-09 16:18:18 -04:00
/// <summary>A SID representing the Everyone Group (S-1-1-0).</summary>
public static SafePSID Everyone = > CreateWellKnown ( WELL_KNOWN_SID_TYPE . WinWorldSid ) ;
2018-11-19 23:18:50 -05:00
/// <summary>
/// Verifies that the revision number is within a known range, and that the number of subauthorities is less than the maximum.
/// </summary>
2017-11-27 13:11:20 -05:00
/// <value><c>true</c> if this instance is a valid SID; otherwise, <c>false</c>.</value>
public bool IsValidSid = > IsValidSid ( this ) ;
2019-08-12 11:04:53 -04:00
/// <summary>Gets the length, in bytes, of the SID.</summary>
/// <value>The SID length, in bytes.</value>
public int Length = > IsValidSid ? GetLengthSid ( this ) : 0 ;
2021-10-07 17:22:32 -04:00
/// <summary>Enumerates the subauthorities in a security identifier (SID). The subauthority values are relative identifiers (RID).</summary>
/// <returns>A sequence of subauthorities.</returns>
public IEnumerable < uint > SubAuthorities = > ( ( PSID ) this ) . GetSubAuthorities ( ) ;
2019-08-15 03:20:08 -04:00
/// <summary>Gets the string used to display in the debugger.</summary>
internal string DebugString
{
get
{
if ( IsInvalid | | IsClosed ) return "NULL" ;
if ( ! IsValidSid ) return "Invalid" ;
var d = ToString ( "D" ) ;
var n = ToString ( "P" ) ;
return d = = n ? $"({d})" : $"{n} ({d})" ;
}
}
/// <summary>Creates a SID for predefined capability.</summary>
2019-11-06 00:52:45 -05:00
/// <param name="capability">
2019-08-15 03:20:08 -04:00
/// Member of the KnownSIDCapability enumeration that specifies which capability the SID will identify.
/// </param>
/// <returns>A <see cref="SafePSID"/> instance.</returns>
public static SafePSID CreateCapability ( KnownSIDCapability capability ) = >
Init ( KnownSIDAuthority . SECURITY_APP_PACKAGE_AUTHORITY , KnownSIDRelativeID . SECURITY_CAPABILITY_BASE_RID , ( int ) capability ) ;
2018-11-19 23:18:50 -05:00
/// <summary>Copies the specified SID from a memory pointer to a <see cref="SafePSID"/> instance.</summary>
2017-11-27 13:11:20 -05:00
/// <param name="psid">The SID pointer. This value remains the responsibility of the caller to release.</param>
2018-11-19 23:18:50 -05:00
/// <returns>A <see cref="SafePSID"/> instance.</returns>
2019-08-09 16:18:18 -04:00
public static SafePSID CreateFromPtr ( IntPtr psid ) = > new SafePSID ( psid ) ;
2017-11-27 13:11:20 -05:00
2019-05-27 21:39:40 -04:00
/// <summary>Creates a SID for predefined aliases.</summary>
/// <param name="WellKnownSidType">Member of the WELL_KNOWN_SID_TYPE enumeration that specifies what the SID will identify.</param>
/// <param name="DomainSid">
/// A pointer to a SID that identifies the domain to use when creating the SID. Pass <c>PSID.NULL</c> to use the local computer.
/// </param>
/// <returns>A <see cref="SafePSID"/> instance.</returns>
2019-11-06 00:52:45 -05:00
public static SafePSID CreateWellKnown ( WELL_KNOWN_SID_TYPE WellKnownSidType , PSID DomainSid = default )
2019-05-27 21:39:40 -04:00
{
var sz = 0 U ;
2019-11-06 00:52:45 -05:00
CreateWellKnownSid ( WellKnownSidType , DomainSid , Null , ref sz ) ;
2019-05-27 21:39:40 -04:00
if ( sz = = 0 ) Win32Error . ThrowLastError ( ) ;
var newSid = new SafePSID ( ( int ) sz ) ;
2019-11-06 00:52:45 -05:00
if ( ! CreateWellKnownSid ( WellKnownSidType , DomainSid , newSid , ref sz ) )
2019-05-27 21:39:40 -04:00
Win32Error . ThrowLastError ( ) ;
return newSid ;
}
2020-09-08 12:40:57 -04:00
/// <summary>Extracts the user account SID associated with a security token.</summary>
/// <param name="hToken">The security token handle.</param>
/// <returns>A <see cref="SafePSID"/> instance of the user account SID associated with a security token.</returns>
public static SafePSID FromToken ( HTOKEN hToken )
{
2021-10-07 12:33:44 -04:00
using var hTok = new SafeHTOKEN ( ( IntPtr ) hToken , false ) ;
return hTok . GetInfo < TOKEN_USER > ( TOKEN_INFORMATION_CLASS . TokenUser ) . User . Sid ;
2020-09-08 12:40:57 -04:00
}
2018-11-19 23:18:50 -05:00
/// <summary>Performs an explicit conversion from <see cref="SafePSID"/> to <see cref="IntPtr"/>.</summary>
/// <param name="psid">The SafePSID instance.</param>
2017-11-27 13:11:20 -05:00
/// <returns>The result of the conversion.</returns>
2018-11-19 23:18:50 -05:00
public static explicit operator IntPtr ( SafePSID psid ) = > psid . DangerousGetHandle ( ) ;
2017-11-27 13:11:20 -05:00
2018-11-19 23:18:50 -05:00
/// <summary>Performs an explicit conversion from <see cref="SafePSID"/> to <see cref="PSID"/>.</summary>
/// <param name="psid">The SafePSID instance.</param>
2017-11-27 13:11:20 -05:00
/// <returns>The result of the conversion.</returns>
2018-11-19 23:18:50 -05:00
public static implicit operator PSID ( SafePSID psid ) = > psid . DangerousGetHandle ( ) ;
2017-11-27 13:11:20 -05:00
2019-06-07 13:01:44 -04:00
/// <summary>Performs an implicit conversion from <see cref="PSID"/> to <see cref="SafePSID"/>.</summary>
/// <param name="psid">The psid.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator SafePSID ( PSID psid ) = > new SafePSID ( psid ) ;
2018-11-19 23:18:50 -05:00
/// <summary>Initializes a new <see cref="SafePSID"/> instance from a SID authority and subauthorities.</summary>
2017-11-27 13:11:20 -05:00
/// <param name="sidAuthority">The SID authority.</param>
/// <param name="subAuth0">The first subauthority.</param>
/// <param name="subAuthorities1to7">Up to seven other subauthorities.</param>
2018-11-19 23:18:50 -05:00
/// <returns>A new <see cref="SafePSID"/> instance.</returns>
2017-11-27 13:11:20 -05:00
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="sidAuthority"/> is null or an invalid length or more than 8 total subauthorities were submitted.
/// </exception>
2018-11-19 23:18:50 -05:00
public static SafePSID Init ( PSID_IDENTIFIER_AUTHORITY sidAuthority , int subAuth0 , params int [ ] subAuthorities1to7 )
2017-11-27 13:11:20 -05:00
{
if ( sidAuthority = = null )
throw new ArgumentOutOfRangeException ( nameof ( sidAuthority ) ) ;
if ( subAuthorities1to7 . Length > 7 )
throw new ArgumentOutOfRangeException ( nameof ( subAuthorities1to7 ) ) ;
2018-11-19 23:18:50 -05:00
AllocateAndInitializeSid ( sidAuthority , ( byte ) ( subAuthorities1to7 . Length + 1 ) ,
subAuth0 ,
subAuthorities1to7 . Length > 0 ? subAuthorities1to7 [ 0 ] : 0 ,
subAuthorities1to7 . Length > 1 ? subAuthorities1to7 [ 1 ] : 0 ,
subAuthorities1to7 . Length > 2 ? subAuthorities1to7 [ 2 ] : 0 ,
subAuthorities1to7 . Length > 3 ? subAuthorities1to7 [ 3 ] : 0 ,
subAuthorities1to7 . Length > 4 ? subAuthorities1to7 [ 4 ] : 0 ,
subAuthorities1to7 . Length > 5 ? subAuthorities1to7 [ 5 ] : 0 ,
subAuthorities1to7 . Length > 6 ? subAuthorities1to7 [ 6 ] : 0 ,
out var res ) ;
return new SafePSID ( res ) ;
2017-11-27 13:11:20 -05:00
}
/// <summary>Implements the operator !=.</summary>
/// <param name="psid1">The psid1.</param>
/// <param name="psid2">The psid2.</param>
/// <returns>The result of the operator.</returns>
2018-11-19 23:18:50 -05:00
public static bool operator ! = ( SafePSID psid1 , SafePSID psid2 ) = > ! ( psid1 = = psid2 ) ;
2017-11-27 13:11:20 -05:00
/// <summary>Implements the operator ==.</summary>
/// <param name="psid1">The psid1.</param>
/// <param name="psid2">The psid2.</param>
/// <returns>The result of the operator.</returns>
2018-11-19 23:18:50 -05:00
public static bool operator = = ( SafePSID psid1 , SafePSID psid2 )
2017-11-27 13:11:20 -05:00
{
if ( ReferenceEquals ( psid1 , psid2 ) ) return true ;
if ( Equals ( null , psid1 ) | | Equals ( null , psid2 ) ) return false ;
return psid1 . Equals ( psid2 ) ;
}
/// <summary>Clones this instance.</summary>
2018-11-19 23:18:50 -05:00
/// <returns>A copy of the current <see cref="SafePSID"/>.</returns>
public SafePSID Clone ( ) = > CreateFromPtr ( handle ) ;
/// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.</returns>
2019-08-12 11:04:53 -04:00
public bool Equals ( SafePSID other ) = > other ! = null & & ( ReferenceEquals ( this , other ) | | EqualSid ( this , other ) ) ;
2017-11-27 13:11:20 -05:00
/// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.</returns>
2018-11-19 23:18:50 -05:00
public bool Equals ( PSID other ) = > Equals ( other . DangerousGetHandle ( ) ) ;
2017-11-27 13:11:20 -05:00
/// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.</returns>
public bool Equals ( IntPtr other ) = > EqualSid ( handle , other ) ;
2019-04-08 13:27:09 -04:00
/// <summary>Determines whether the specified <see cref="object"/> is equal to the current <see cref="object"/>.</summary>
2017-11-27 13:11:20 -05:00
/// <param name="obj">The object to compare with the current object.</param>
2019-04-10 14:13:59 -04:00
/// <returns>true if the specified <see cref="object"/> is equal to the current <see cref="object"/>; otherwise, false.</returns>
2021-10-07 17:22:32 -04:00
public override bool Equals ( object obj ) = > obj switch
2017-11-27 13:11:20 -05:00
{
2021-10-07 17:22:32 -04:00
SafePSID psid2 = > Equals ( psid2 ) ,
PSID psidh = > Equals ( psidh ) ,
IntPtr ptr = > Equals ( ptr ) ,
_ = > false
} ;
2017-11-27 13:11:20 -05:00
2018-11-19 23:18:50 -05:00
/// <summary>Gets the binary form of this SafePSID.</summary>
2017-11-27 13:11:20 -05:00
/// <returns>An array of bytes containing the Sid.</returns>
2019-08-09 16:18:18 -04:00
public byte [ ] GetBinaryForm ( ) = > GetBytes ( 0 , Size ) ;
2017-11-27 13:11:20 -05:00
/// <summary>Returns a hash code for this instance.</summary>
/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
public override int GetHashCode ( ) = > base . GetHashCode ( ) ;
2019-04-08 13:27:09 -04:00
/// <summary>Returns a <see cref="string"/> that represents this instance.</summary>
/// <returns>A <see cref="string"/> that represents this instance.</returns>
2019-08-15 03:20:08 -04:00
public override string ToString ( ) = > ToString ( null ) ;
/// <summary>Converts the value of this security identifier (SID) to its equivalent string representation according to the provided format specifier.</summary>
/// <param name="format">
/// A single format specifier that indicates how to format the value of this security identifier (SID). The format parameter can be
2020-01-05 22:50:42 -05:00
/// "B" (binary), "D" (sddl), "N" (name), or "P" (upn). If format is null or an empty string (""), "D" is used.
2019-08-15 03:20:08 -04:00
/// </param>
/// <returns>The value of this security identifier (SID), in the specified format.</returns>
/// <exception cref="ArgumentException">SID value is not a valid SID. - pSid</exception>
2020-01-05 22:50:42 -05:00
/// <exception cref="FormatException">The value of format is not null, an empty string (""), "B" (binary), "D" (sddl), "N" (name), or "P" (upn).</exception>
2019-08-15 03:20:08 -04:00
/// <remarks>
/// <para>The following table shows the accepted format specifiers for the format parameter.</para>
/// <list type="table">
/// <item>
/// <description>Specifier</description>
/// <description>Format of return value</description>
/// </item>
/// <item>
/// <description>"B"</description>
/// <description>
/// <para>Binary hex dump representation of the SID.</para>
/// </description>
/// </item>
/// <item>
/// <description>"D"</description>
/// <description>SDDL representation of the SID.</description>
/// </item>
/// <item>
/// <description>"N"</description>
/// <description>The NT4 style name (domain\username) corresponding to the SID.</description>
/// </item>
/// <item>
/// <description>"P"</description>
/// <description>The internet style name (UPN) corresponding to the SID.</description>
/// </item>
/// </list>
/// </remarks>
public string ToString ( string format )
2019-08-09 16:18:18 -04:00
{
2019-08-15 03:20:08 -04:00
try { return ( ( PSID ) handle ) . ToString ( format ) ; }
2019-08-09 16:18:18 -04:00
catch { return ! IsInvalid & & ! IsClosed ? "Invalid" : "0" ; }
}
2017-11-27 13:11:20 -05:00
/// <summary>Creates a new object that is a copy of the current instance.</summary>
/// <returns>A new object that is a copy of this instance.</returns>
object ICloneable . Clone ( ) = > Clone ( ) ;
2019-06-25 19:11:42 -04:00
private static byte [ ] GetBytes ( System . Security . Principal . SecurityIdentifier si )
{
var b = new byte [ si . BinaryLength ] ;
si . GetBinaryForm ( b , 0 ) ;
return b ;
}
2017-11-27 13:11:20 -05:00
}
2019-08-09 16:18:18 -04:00
/// <summary>Provides an array of SID pointers whose memory is disposed after use.</summary>
/// <seealso cref="Vanara.PInvoke.SafeHANDLE"/>
2019-11-06 00:52:45 -05:00
/// <seealso cref="System.Collections.Generic.IReadOnlyList{T}"/>
2019-08-09 16:18:18 -04:00
public class SafePSIDArray : SafeHANDLE , IReadOnlyList < PSID >
{
private List < SafePSID > items ;
/// <summary>Initializes a new instance of the <see cref="SafePSIDArray"/> class and assigns an existing handle.</summary>
/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
2019-08-12 11:04:53 -04:00
/// <param name="count">The count of PSID array values pointed to by <paramref name="preexistingHandle"/>.</param>
2019-08-09 16:18:18 -04:00
/// <param name="ownsHandle">
2019-08-12 11:04:53 -04:00
/// <see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not
/// recommended). If <see langword="true"/>, the individually allocated values for each PSID will also be released.
2019-08-09 16:18:18 -04:00
/// </param>
2019-08-12 11:04:53 -04:00
public SafePSIDArray ( IntPtr preexistingHandle , int count , bool ownsHandle = true ) : base ( preexistingHandle , ownsHandle )
{
if ( ownsHandle )
Count = count ;
else
items = new List < SafePSID > ( handle . ToIEnum < IntPtr > ( count ) . Select ( p = > new SafePSID ( p ) ) ) ;
}
2019-08-09 16:18:18 -04:00
/// <summary>Initializes a new instance of the <see cref="SafePSIDArray"/> class.</summary>
/// <param name="pSIDs">A list of <see cref="SafePSID"/> instances.</param>
2019-08-12 11:04:53 -04:00
public SafePSIDArray ( IEnumerable < SafePSID > pSIDs ) : this ( pSIDs ? . Select ( p = > ( PSID ) p ) )
2019-08-09 16:18:18 -04:00
{
}
/// <summary>Initializes a new instance of the <see cref="SafePSIDArray"/> class.</summary>
/// <param name="pSIDs">A list of <see cref="SafePSID"/> instances.</param>
public SafePSIDArray ( IEnumerable < PSID > pSIDs ) : base ( )
{
2019-08-12 11:04:53 -04:00
if ( pSIDs is null ) throw new ArgumentNullException ( nameof ( pSIDs ) ) ;
2019-08-09 16:18:18 -04:00
items = pSIDs . Select ( p = > new SafePSID ( p ) ) . ToList ( ) ;
2019-08-17 23:13:57 -04:00
SetHandle ( items . Select ( p = > ( IntPtr ) p ) . MarshalToPtr < IntPtr > ( i = > LocalAlloc ( LMEM . LPTR , i ) . DangerousGetHandle ( ) , out _ ) ) ;
2019-08-09 16:18:18 -04:00
}
/// <summary>Initializes a new instance of the <see cref="SafePSIDArray"/> class.</summary>
private SafePSIDArray ( ) : base ( ) { }
/// <summary>Gets or sets the length of the array. This value must be set in order to interact with the elements.</summary>
/// <value>The length.</value>
public int Count
{
get = > items ? . Count ? ? throw new InvalidOperationException ( "The length must be set before using this function." ) ;
set
{
2019-08-12 11:04:53 -04:00
if ( items ! = null ) throw new InvalidOperationException ( "The length can only be set for partially initialized arrays." ) ;
items = new List < SafePSID > ( ) ;
foreach ( var psid in handle . ToIEnum < IntPtr > ( value ) )
{
items . Add ( new SafePSID ( psid ) ) ;
LocalFree ( psid ) ;
}
2019-08-09 16:18:18 -04:00
}
}
/// <summary>Gets the <see cref="PSID"/> at the specified index.</summary>
/// <value>The <see cref="PSID"/>.</value>
/// <param name="index">The index.</param>
/// <returns>The PSID at the specified index.</returns>
/// <exception cref="InvalidOperationException">The length must be set before using this function.</exception>
public PSID this [ int index ] = > items ? [ index ] ? ? throw new InvalidOperationException ( "The length must be set before using this function." ) ;
2019-11-06 00:52:45 -05:00
/// <summary>Performs an implicit conversion from <see cref="SafePSIDArray"/> to <see cref="PSID"/>[].</summary>
2019-08-09 16:18:18 -04:00
/// <param name="a">The <see cref="SafePSIDArray"/> instance.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator PSID [ ] ( SafePSIDArray a ) = > a . items . ConvertAll ( p = > ( PSID ) p ) . ToArray ( ) ;
/// <summary>Returns an enumerator that iterates through the collection.</summary>
/// <returns>A <see cref="IEnumerator{PSID}"/> that can be used to iterate through the collection.</returns>
public IEnumerator < PSID > GetEnumerator ( ) = > items . ConvertAll ( p = > ( PSID ) p ) . GetEnumerator ( ) ;
/// <inheritdoc/>
IEnumerator IEnumerable . GetEnumerator ( ) = > ( ( IEnumerable < SafePSID > ) items ) . GetEnumerator ( ) ;
/// <inheritdoc/>
protected override bool InternalReleaseHandle ( )
{
if ( items ! = null )
foreach ( var p in items )
p . Dispose ( ) ;
return LocalFree ( handle ) = = HLOCAL . NULL ;
}
}
2017-11-27 13:11:20 -05:00
}
2019-08-15 03:20:08 -04:00
/// <summary>Extension methods for PSID instances.</summary>
public static class PSIDExtensions
{
/// <summary>Determines equality of two PSID instances.</summary>
/// <param name="psid1">The first PSID.</param>
/// <param name="psid2">The second PSID.</param>
/// <returns><see langword="true"/> if the SID structures are equal; <see langword="false"/> otherwise.</returns>
public static bool Equals ( this PSID psid1 , PSID psid2 ) = > AdvApi32 . EqualSid ( psid1 , psid2 ) ;
2021-10-07 17:22:32 -04:00
/// <summary>
/// The <c>GetAuthority</c> function returns a pointer to the SID_IDENTIFIER_AUTHORITY structure in a specified security identifier (SID).
/// </summary>
/// <param name="pSid">
/// <para>A pointer to the SID structure for which a pointer to the SID_IDENTIFIER_AUTHORITY structure is returned.</para>
/// <para>
/// This function does not handle SID structures that are not valid. Call the IsValidSid function to verify that the <c>SID</c>
/// structure is valid before you call this function.
/// </para>
/// </param>
/// <returns>
/// <para>
/// If the function succeeds, the return value is a pointer to the SID_IDENTIFIER_AUTHORITY structure for the specified SID structure.
/// </para>
/// <para>
/// If the function fails, the return value is undefined. The function fails if the SID structure pointed to by the pSid parameter
/// is not valid. To get extended error information, call GetLastError.
/// </para>
/// </returns>
/// <remarks>
/// This function uses a 32-bit RID value. For applications that require a larger RID value, use CreateWellKnownSid and related functions.
/// </remarks>
public static AdvApi32 . PSID_IDENTIFIER_AUTHORITY GetAuthority ( this PSID pSid ) = > AdvApi32 . GetSidIdentifierAuthority ( pSid ) ;
2019-08-15 03:20:08 -04:00
/// <summary>Gets the binary form of the SID structure.</summary>
/// <param name="pSid">The SID structure pointer.</param>
/// <returns>The binary form (byte array) of the SID structure.</returns>
public static byte [ ] GetBinaryForm ( this PSID pSid ) = > pSid . IsValidSid ( ) ? ( ( IntPtr ) pSid ) . ToArray < byte > ( pSid . Length ( ) ) : ( new byte [ 0 ] ) ;
2020-09-08 12:40:57 -04:00
/// <summary>
/// The <c>GetDomainSid</c> function receives a security identifier (SID) and returns a SID representing the domain of that SID.
/// </summary>
/// <param name="pSid">A pointer to the SID to examine.</param>
/// <returns>An allocated safe pointer to a SID representing the domain.</returns>
public static AdvApi32 . SafePSID GetDomainSid ( this PSID pSid )
{
Win32Error . ThrowLastErrorIfFalse ( AdvApi32 . GetWindowsAccountDomainSid ( pSid , out var pDomSid ) ) ;
return pDomSid ;
}
2021-10-07 17:22:32 -04:00
/// <summary>Enumerates the subauthorities in a security identifier (SID). The subauthority values are relative identifiers (RID).</summary>
/// <param name="pSid">A pointer to the SID structure from which a pointer to a subauthority is to be returned.</param>
/// <returns>A sequence of subauthorities.</returns>
public static IEnumerable < uint > GetSubAuthorities ( this PSID pSid )
{
for ( uint i = 0 ; i < AdvApi32 . GetSidSubAuthorityCount ( pSid ) ; i + + )
yield return AdvApi32 . GetSidSubAuthority ( pSid , i ) ;
}
2019-08-15 03:20:08 -04:00
/// <summary>
/// Validates a security identifier (SID) by verifying that the revision number is within a known range, and that the number of
/// subauthorities is less than the maximum.
/// </summary>
/// <param name="pSid">A pointer to the SID structure to validate. This parameter cannot be NULL.</param>
/// <returns>
/// If the SID structure is valid, the return value is <see langword="true"/>. If the SID structure is not valid, the return value is <see langword="false"/>.
/// </returns>
public static bool IsValidSid ( this PSID pSid ) = > AdvApi32 . IsValidSid ( pSid ) ;
/// <summary>Returns the length, in bytes, of a valid security identifier (SID).</summary>
/// <param name="pSid">A pointer to the SID structure whose length is returned. The structure is assumed to be valid.</param>
/// <returns>
/// If the SID structure is valid, the return value is the length, in bytes, of the SID structure. If the SID structure is not valid,
/// the return value is 0.
/// </returns>
public static int Length ( this PSID pSid ) = > AdvApi32 . IsValidSid ( pSid ) ? AdvApi32 . GetLengthSid ( pSid ) : 0 ;
/// <summary>Converts the value of a security identifier (SID) to its equivalent string representation according to the provided format specifier.</summary>
/// <param name="pSid">A pointer to a valid SID structure.</param>
/// <param name="format">
/// A single format specifier that indicates how to format the value of this security identifier (SID). The format parameter can be
2020-01-05 22:50:42 -05:00
/// "B" (binary), "D" (sddl), "N" (name), or "P" (upn). If format is null or an empty string (""), "D" is used.
2019-08-15 03:20:08 -04:00
/// </param>
/// <returns>The value of this security identifier (SID), in the specified format.</returns>
/// <exception cref="ArgumentException">SID value is not a valid SID. - pSid</exception>
/// <exception cref="FormatException">The value of format is not null, an empty string (""), "B", "D", "N", or "P".</exception>
/// <remarks>
/// <para>The following table shows the accepted format specifiers for the format parameter.</para>
/// <list type="table">
/// <item>
/// <description>Specifier</description>
/// <description>Format of return value</description>
/// </item>
/// <item>
/// <description>"B"</description>
/// <description>
/// <para>Binary hex dump representation of the SID.</para>
/// </description>
/// </item>
/// <item>
/// <description>"D"</description>
/// <description>SDDL representation of the SID.</description>
/// </item>
/// <item>
/// <description>"N"</description>
/// <description>The NT4 style name (domain\username) corresponding to the SID.</description>
/// </item>
/// <item>
/// <description>"P"</description>
/// <description>The internet style name (UPN) corresponding to the SID.</description>
/// </item>
/// </list>
/// </remarks>
public static string ToString ( this PSID pSid , string format )
{
if ( ! pSid . IsValidSid ( ) )
throw new ArgumentException ( "SID value is not a valid SID." , nameof ( pSid ) ) ;
switch ( format )
{
case "B" :
var len = pSid . Length ( ) ;
return pSid . GetBinaryForm ( ) . ToHexDumpString ( len , len , 0 ) . Trim ( ' ' , '\r' , '\n' ) ;
case "D" :
case null :
case "" :
2019-11-03 23:27:26 -05:00
try { return AdvApi32 . ConvertSidToStringSid ( pSid ) ; }
catch { goto case "B" ; }
2019-08-15 03:20:08 -04:00
case "N" :
case "P" :
using ( var hPol = AdvApi32 . LsaOpenPolicy ( AdvApi32 . LsaPolicyRights . POLICY_ALL_ACCESS ) )
{
var flag = format = = "P" ? AdvApi32 . LsaLookupSidsFlags . LSA_LOOKUP_PREFER_INTERNET_NAMES : 0 ;
try
{
AdvApi32 . LsaLookupSids2 ( hPol , flag , 1 , new [ ] { pSid } , out var memDoms , out var memNames ) . ThrowIfFailed ( ) ;
memDoms . Dispose ( ) ;
using ( memNames )
{
return memNames . ToStructure < AdvApi32 . LSA_TRANSLATED_NAME > ( ) . Name ;
}
}
catch ( Exception )
{
goto case "D" ;
}
}
default :
throw new FormatException ( ) ;
}
}
}
2017-11-27 13:11:20 -05:00
}