146 lines
6.1 KiB
C#
146 lines
6.1 KiB
C#
using System;
|
|
using System.Security.Principal;
|
|
|
|
namespace Microsoft.Win32.TaskScheduler
|
|
{
|
|
/// <summary>Represents a system account.</summary>
|
|
internal class User : IEquatable<User>, IDisposable
|
|
{
|
|
private static readonly WindowsIdentity cur = WindowsIdentity.GetCurrent();
|
|
private SecurityIdentifier sid;
|
|
|
|
/// <summary>Initializes a new instance of the <see cref="User"/> class.</summary>
|
|
/// <param name="userName">
|
|
/// Name of the user. This can be in the format <c>DOMAIN\username</c> or <c>username@domain.com</c> or <c>username</c> or
|
|
/// <c>null</c> (for current user).
|
|
/// </param>
|
|
public User(string userName = null)
|
|
{
|
|
if (string.IsNullOrEmpty(userName)) userName = null;
|
|
// 2018-03-02: Hopefully not a breaking change, but by adding in the comparison of an account name without a domain and the
|
|
// current user, there is a chance that current implementations will break given the condition that a local account with the same
|
|
// name as a domain account exists and the intention was to prefer the local account. In such a case, the developer should
|
|
// prepend the user name in TaskDefinition.Principal.UserId with the machine name of the local machine.
|
|
if (userName == null || cur.Name.Equals(userName, StringComparison.InvariantCultureIgnoreCase) || GetUser(cur.Name).Equals(userName, StringComparison.InvariantCultureIgnoreCase))
|
|
{
|
|
Identity = cur;
|
|
sid = Identity.User;
|
|
}
|
|
else if (userName.Contains("\\") && !userName.StartsWith(@"NT AUTHORITY\"))
|
|
{
|
|
try
|
|
{
|
|
using (var ds = new NativeMethods.DomainService())
|
|
{
|
|
Identity = new WindowsIdentity(ds.CrackName(userName));
|
|
sid = Identity.User;
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
if (Identity == null)
|
|
{
|
|
if (userName != null && userName.Contains("@"))
|
|
{
|
|
Identity = new WindowsIdentity(userName);
|
|
sid = Identity.User;
|
|
}
|
|
|
|
if (Identity == null && userName != null)
|
|
{
|
|
var ntacct = new NTAccount(userName);
|
|
try { sid = (SecurityIdentifier)ntacct.Translate(typeof(SecurityIdentifier)); } catch { }
|
|
}
|
|
}
|
|
|
|
string GetUser(string domUser)
|
|
{
|
|
var split = domUser.Split('\\');
|
|
return split.Length == 2 ? split[1] : domUser;
|
|
}
|
|
}
|
|
|
|
/// <summary>Initializes a new instance of the <see cref="User"/> class.</summary>
|
|
/// <param name="wid">The <see cref="WindowsIdentity"/>.</param>
|
|
internal User(WindowsIdentity wid) { Identity = wid; sid = wid.User; }
|
|
|
|
/// <summary>Gets the current user.</summary>
|
|
/// <value>The current user.</value>
|
|
public static User Current => new User(cur);
|
|
|
|
/// <summary>Gets the identity.</summary>
|
|
/// <value>The identity.</value>
|
|
public WindowsIdentity Identity { get; private set; }
|
|
|
|
/// <summary>Gets a value indicating whether this instance is in an administrator role.</summary>
|
|
/// <value><c>true</c> if this instance is an admin; otherwise, <c>false</c>.</value>
|
|
public bool IsAdmin => Identity != null ? new WindowsPrincipal(Identity).IsInRole(WindowsBuiltInRole.Administrator) : false;
|
|
|
|
/// <summary>Gets a value indicating whether this instance is the interactive user.</summary>
|
|
/// <value><c>true</c> if this instance is the current user; otherwise, <c>false</c>.</value>
|
|
public bool IsCurrent => Identity?.User.Equals(cur.User) ?? false;
|
|
|
|
/// <summary>Gets a value indicating whether this instance is a service account.</summary>
|
|
/// <value><c>true</c> if this instance is a service account; otherwise, <c>false</c>.</value>
|
|
public bool IsServiceAccount
|
|
{
|
|
get
|
|
{
|
|
try
|
|
{
|
|
return (sid != null && (sid.IsWellKnown(WellKnownSidType.LocalSystemSid) || sid.IsWellKnown(WellKnownSidType.NetworkServiceSid) || sid.IsWellKnown(WellKnownSidType.LocalServiceSid)));
|
|
}
|
|
catch { }
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets a value indicating whether this instance is the SYSTEM account.</summary>
|
|
/// <value><c>true</c> if this instance is the SYSTEM account; otherwise, <c>false</c>.</value>
|
|
public bool IsSystem => sid != null && sid.IsWellKnown(WellKnownSidType.LocalSystemSid);
|
|
|
|
/// <summary>Gets the SID string.</summary>
|
|
/// <value>The SID string.</value>
|
|
public string SidString => sid?.ToString();
|
|
|
|
/// <summary>Gets the NT name (DOMAIN\username).</summary>
|
|
/// <value>The name of the user.</value>
|
|
public string Name => Identity?.Name ?? ((NTAccount)sid?.Translate(typeof(NTAccount)))?.Value;
|
|
|
|
/// <summary>Create a <see cref="User"/> instance from a SID string.</summary>
|
|
/// <param name="sid">The SID string.</param>
|
|
/// <returns>A <see cref="User"/> instance.</returns>
|
|
public static User FromSidString(string sid) => new User(((NTAccount)new SecurityIdentifier(sid).Translate(typeof(NTAccount))).Value);
|
|
|
|
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
|
|
public void Dispose() => Identity?.Dispose();
|
|
|
|
/// <summary>Determines whether the specified <see cref="System.Object"/>, is equal to this instance.</summary>
|
|
/// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
|
|
/// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.</returns>
|
|
public override bool Equals(object obj)
|
|
{
|
|
if (obj is User user)
|
|
return Equals(user);
|
|
if (obj is WindowsIdentity wid && sid != null)
|
|
return sid.Equals(wid.User);
|
|
try
|
|
{
|
|
if (obj is string un)
|
|
return Equals(new User(un));
|
|
}
|
|
catch { }
|
|
return base.Equals(obj);
|
|
}
|
|
|
|
/// <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(User other) => (other != null && sid != null) ? sid.Equals(other.sid) : false;
|
|
|
|
/// <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() => sid?.GetHashCode() ?? 0;
|
|
}
|
|
} |