PowerShell/src/Microsoft.PowerShell.LocalAccounts/LocalAccounts/Extensions.cs
PowerShell Team c748652c34 Copy all mapped files from [SD:725290]
commit 8cec8f150da7583b7af5efbe2853efee0179750c
2016-07-28 23:23:03 -07:00

203 lines
7.5 KiB
C#

using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
using System.Text.RegularExpressions;
using Microsoft.PowerShell.Commands;
using Microsoft.PowerShell.LocalAccounts;
namespace System.Management.Automation.SecurityAccountsManager.Extensions
{
/// <summary>
/// Provides extension methods for the Cmdlet class
/// </summary>
internal static class CmdletExtensions
{
/// <summary>
/// Attempt to create a SID from a string.
/// </summary>
/// <param name="cmdlet">The cmdlet being extended with this method.</param>
/// <param name="s">The string to be converted to a SID.</param>
/// <param name="allowSidConstants">
/// A boolean indicating whether SID constants, such as "BA", are considered.
/// </param>
/// <returns>
/// A <see cref="SecurityIdentifier"/> object if the conversion was successful,
/// null otherwise.
/// </returns>
internal static SecurityIdentifier TrySid(this Cmdlet cmdlet,
string s,
bool allowSidConstants = false)
{
if (!allowSidConstants)
if (!(s.Length > 2 && s.StartsWith("S-", StringComparison.Ordinal) && Char.IsDigit(s[2])))
return null;
SecurityIdentifier sid = null;
try
{
sid = new SecurityIdentifier(s);
}
catch (ArgumentException)
{
// do nothing here, just fall through to the return
}
return sid;
}
}
/// <summary>
/// Provides extension methods for the PSCmdlet class
/// </summary>
internal static class PSExtensions
{
/// <summary>
/// Determine if a given parameter was provided to the cmdlet
/// </summary>
/// <param name="cmdlet">
/// The <see cref="PSCmdlet"/> object to check.
/// </param>
/// <param name="parameterName">
/// A string containing the name of the parameter. This should be in the
/// same letter-casing as the defined parameter.
/// </param>
/// <returns>
/// True if the specified parameter was given on the cmdlet invocation,
/// false otherwise.
/// </returns>
internal static bool HasParameter(this PSCmdlet cmdlet, string parameterName)
{
var invocation = cmdlet.MyInvocation;
if (invocation != null)
{
var parameters = invocation.BoundParameters;
if (parameters != null)
{
// PowerShell sets the parameter names in the BoundParameters dictionary
// to their "proper" casing, so we don't have to do a case-insensitive search.
if (parameters.ContainsKey(parameterName))
return true;
}
}
return false;
}
}
/// <summary>
/// Provides extension methods for the SecurityIdentifier class.
/// </summary>
internal static class SidExtensions
{
/// <summary>
/// Get the Relative ID (RID) from a <see cref="SecurityIdentifier"/> object.
/// </summary>
/// <param name="sid">The SecurityIdentifier containing the desired Relative ID.</param>
/// <returns>
/// A UInt32 value containing the Relative ID in the SecurityIdentifier.
/// </returns>
internal static UInt32 GetRid(this SecurityIdentifier sid)
{
byte[] sidBinary = new byte[sid.BinaryLength];
sid.GetBinaryForm(sidBinary, 0);
return System.BitConverter.ToUInt32(sidBinary, sidBinary.Length-4);
}
/// <summary>
/// Gets the Identifier Authority portion of a <see cref="SecurityIdentifier"/>
/// </summary>
/// <param name="sid">The SecurityIdentifier containing the desired Authority.</param>
/// <returns>
/// A long integer value containing the SecurityIdentifier's Identifier Authority value.
/// </returns>
/// <remarks>
/// This method is used primarily for determining the Source of a Principal.
/// The Win32 API LsaLookupUserAccountType function does not (yet) properly
/// identify MicrosoftAccount principals.
/// </remarks>
internal static long GetIdentifierAuthority(this SecurityIdentifier sid)
{
byte[] sidBinary = new byte[sid.BinaryLength];
sid.GetBinaryForm(sidBinary, 0);
// The Identifier Authority is six bytes wide,
// in big-endian format, starting at the third byte
long authority = (long) (((long)sidBinary[2]) << 40) +
(((long)sidBinary[3]) << 32) +
(((long)sidBinary[4]) << 24) +
(((long)sidBinary[5]) << 16) +
(((long)sidBinary[6]) << 8) +
(((long)sidBinary[7]) );
return authority;
}
internal static bool IsMsaAccount(this SecurityIdentifier sid)
{
return sid.GetIdentifierAuthority() == 11;
}
}
internal static class SecureStringExtensions
{
/// <summary>
/// Extension method to extract clear text from a
/// <see cref="System.Security.SecureString"/> object.
/// </summary>
/// <param name="str">
/// This SecureString object, containing encrypted text.
/// </param>
/// <returns>
/// A string containing the SecureString object's original text.
/// </returns>
internal static string AsString(this SecureString str)
{
#if CORECLR
IntPtr buffer = SecureStringMarshal.SecureStringToCoTaskMemUnicode(str);
string clear = Marshal.PtrToStringUni(buffer);
SecureStringMarshal.ZeroFreeCoTaskMemUnicode(buffer);
#else
var bstr = Marshal.SecureStringToBSTR(str);
string clear = Marshal.PtrToStringAuto(bstr);
Marshal.ZeroFreeBSTR(bstr);
#endif
return clear;
}
}
internal static class ExceptionExtensions
{
internal static ErrorRecord MakeErrorRecord(this Exception ex,
string errorId,
ErrorCategory errorCategory,
object target = null)
{
return new ErrorRecord(ex, errorId, errorCategory, target);
}
internal static ErrorRecord MakeErrorRecord(this Exception ex, object target = null)
{
// This part is somewhat less than beautiful, but it prevents
// having to have multiple exception handlers in every cmdlet command.
var exTemp = ex as LocalAccountsException;
if (exTemp != null)
return MakeErrorRecord(exTemp, target ?? exTemp.Target);
return new ErrorRecord(ex,
Strings.UnspecifiedError,
ErrorCategory.NotSpecified,
target);
}
internal static ErrorRecord MakeErrorRecord(this LocalAccountsException ex, object target = null)
{
return ex.MakeErrorRecord(ex.ErrorName, ex.ErrorCategory, target ?? ex.Target);
}
}
}