1543 lines · 62.5 KB · C#
RawDownload
//******************************************************************************************************//  WindowsUserInfo.cs - Gbtc////  Copyright © 2014, Grid Protection Alliance.  All Rights Reserved.////  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See//  the NOTICE file distributed with this work for additional information regarding copyright ownership.//  The GPA licenses this file to you under the MIT License (MIT), the "License"; you may//  not use this file except in compliance with the License. You may obtain a copy of the License at:////      http://www.opensource.org/licenses/MIT////  Unless agreed to in writing, the subject software distributed under the License is distributed on an//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the//  License for the specific language governing permissions and limitations.////  Code Modification History://  ----------------------------------------------------------------------------------------------------//  08/27/2014 - J. Ritchie Carroll//       Generated original version of source code.////****************************************************************************************************** using System;using System.Collections;using System.Collections.Generic;using System.DirectoryServices;using System.IO;using System.Linq;using System.Management;using System.Reflection;using System.Runtime.InteropServices;using System.Security;using System.Security.Principal;using System.Text.RegularExpressions;using System.Threading;using GSF.Configuration;using GSF.Diagnostics;using GSF.Interop;using GSF.IO;using Microsoft.Win32; #if !MONOusing System.DirectoryServices.AccountManagement;#endif // ReSharper disable RedundantExplicitParamsArrayCreationnamespace GSF.Identity{    // Windows implementation of key UserInfo class elements    internal sealed class WindowsUserInfo : IUserInfo    {        #region [ Members ]         // Constants        private const string LogonDomainRegistryKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon";        private const string LogonDomainRegistryValue = "DefaultDomainName";         // Fields        private readonly UserInfo m_parent;        private DirectoryEntry m_userEntry;        private bool m_domainRespondsForUser;        private readonly bool m_useLegacyGroupLookups;        private bool m_disposed;        private bool m_initialized;         #endregion         #region [ Constructors ]         public WindowsUserInfo(UserInfo parent)        {            m_parent = parent;             // Attempt to attach to power mode changed system event            try            {                SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;            }            catch            {                // This event will not be raised when running from a Windows service since                // a service does not establish a message loop.            }             // Attempt to get configuration flag for using legacy group lookups            try            {                ConfigurationFile config = ConfigurationFile.Current;                CategorizedSettingsElementCollection settings = config.Settings[m_parent.SettingsCategory];                settings.Add("UseLegacyGroupLookups", m_useLegacyGroupLookups, "Flag that determines if group based lookups for local users should use legacy algorithm. Enabling may speed up authentication when using local accounts.");                m_useLegacyGroupLookups = settings["UseLegacyGroupLookups"].ValueAs(m_useLegacyGroupLookups);            }            catch (Exception ex)            {                Logger.SwallowException(ex, "Failed while checking configuration for legacy group lookups");            }        }         ~WindowsUserInfo()        {            Dispose(false);        }         #endregion         #region [ Properties ]         public bool DomainRespondsForUser        {            get            {                if (!m_initialized)                {                    // Attempt to initialize                    try                    {                        Initialize();                    }                    catch (InitializationException)                    {                        // Initialization failures are due to domain not responding,                        // member flag is set in Initialize() method.                    }                }                 return m_domainRespondsForUser;            }        }         public bool Exists        {            get            {                bool exists = false;                 if (!m_initialized)                {                    // Attempt to initialize                    try                    {                        Initialize();                    }                    catch (InitializationException)                    {                        // User could not be found - this could simply mean that ActiveDirectory is unavailable (e.g., laptop disconnected from the domain).                        // In this case, if user logged in with cached credentials they are at least authenticated so we can assume that the user exists...                        IPrincipal principal = m_parent.PassthroughPrincipal;                        IIdentity identity = principal?.Identity ?? WindowsIdentity.GetCurrent();                         exists =                            !string.IsNullOrEmpty(m_parent.LoginID) &&                            identity.Name.Equals(m_parent.LoginID, StringComparison.OrdinalIgnoreCase) &&                            identity.IsAuthenticated;                    }                }                 if (!exists)                {                    if (IsLocalAccount)                    {                        try                        {                            exists = DirectoryEntry.Exists($"WinNT://{m_parent.Domain}/{m_parent.UserName}");                        }                        catch                        {                            exists = false;                        }                    }                    else                    {                        exists = !(m_userEntry is null);                    }                }                 return exists;            }        }         public bool Enabled { get; set; }         public DateTime LastLogon        {            get            {                if (Enabled)                {                    try                    {                        return IsLocalAccount ?                             DateTime.Parse(GetUserPropertyValue("lastLogin")) :                             DateTime.FromFileTime(ConvertToLong(GetUserPropertyValueCollection("lastLogon").Value));                    }                    catch                    {                        return DateTime.MinValue;                    }                }                 return DateTime.MinValue;            }        }         public DateTime AccountCreationDate        {            get            {                if (Enabled)                {                    try                    {                        if (IsLocalAccount)                        {                            string profilePath = GetUserPropertyValue("profile");                             if (string.IsNullOrEmpty(profilePath) || !Directory.Exists(profilePath))                            {                                // Remove any trailing directory separator character from the file path.                                string rootFolder = FilePath.AddPathSuffix(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile));                                string userFolder = FilePath.GetLastDirectoryName(rootFolder);                                int folderLocation = rootFolder.LastIndexOf(userFolder, StringComparison.OrdinalIgnoreCase);                                 // Remove user profile name for current user (this class may be for user other than owner of current thread)                                                            rootFolder = FilePath.AddPathSuffix(rootFolder.Substring(0, folderLocation));                                 // Create profile path for user referenced in this UserInfo class                                profilePath = FilePath.AddPathSuffix(rootFolder + m_parent.UserName);                            }                             return Directory.GetCreationTime(profilePath);                        }                         return Convert.ToDateTime(GetUserPropertyValue("whenCreated"));                    }                    catch                    {                        return DateTime.MinValue;                    }                }                 return DateTime.MinValue;            }        }         public DateTime NextPasswordChangeDate        {            get            {                DateTime passwordChangeDate = DateTime.MaxValue;                 if (Enabled && !m_parent.PasswordCannotChange && !m_parent.PasswordDoesNotExpire)                {                    try                    {                        if (IsLocalAccount)                        {                            Ticks maxPasswordTicksAge = MaximumPasswordAge;                             if (maxPasswordTicksAge >= 0)                            {                                // WinNT properties are in seconds, not ticks                                long passwordAge = long.Parse(GetUserPropertyValue("passwordAge"));                                long maxPasswordAge = (long)maxPasswordTicksAge.ToSeconds();                                 if (passwordAge > maxPasswordAge || GetUserPropertyValue("passwordExpired").ParseBoolean())                                {                                    // User must change password on next logon.                                    passwordChangeDate = DateTime.UtcNow;                                }                                else                                {                                    // User must change password periodically.                                    passwordChangeDate = DateTime.UtcNow.AddSeconds(maxPasswordAge - passwordAge);                                }                            }                        }                        else                        {                            long passwordSetOn = ConvertToLong(GetUserPropertyValueCollection("pwdLastSet").Value);                             if (passwordSetOn == 0)                            {                                // User must change password on next logon.                                passwordChangeDate = DateTime.UtcNow;                            }                            else                            {                                // User must change password periodically.                                long maxPasswordAge = MaximumPasswordAge;                                 // Ignore extremes                                if (maxPasswordAge != long.MaxValue && maxPasswordAge > 0)                                    passwordChangeDate = DateTime.FromFileTime(passwordSetOn).AddDays(TimeSpan.FromTicks(maxPasswordAge).Duration().Days);                            }                        }                    }                    catch                    {                        return DateTime.MaxValue;                    }                }                 return passwordChangeDate;            }        }         public int LocalUserAccountControl        {            get            {                int userAccountControl = -1;                 if (Enabled && IsLocalAccount)                {                    string userPropertyValue = GetUserPropertyValue("userFlags");                     if (string.IsNullOrEmpty(userPropertyValue))                        throw new SecurityException(string.Format(UserInfo.SecurityExceptionFormat, "Local", UserInfo.CurrentUserID, "local machine accounts"));                     if (!int.TryParse(userPropertyValue, out userAccountControl))                        throw new InvalidOperationException(string.Format(UserInfo.UnknownErrorFormat, m_parent.LoginID, userPropertyValue));                }                 return userAccountControl;            }        }         public Ticks MaximumPasswordAge        {            get            {                if (!Enabled)                    return -1;                 string maxAgePropertyValue = string.Empty;                 if (IsLocalAccount)                {                    maxAgePropertyValue = GetUserPropertyValue("maxPasswordAge");                }                else                {                    WindowsImpersonationContext currentContext = null;                     try                    {                        currentContext = m_parent.ImpersonatePrivilegedAccount();                         using (DirectorySearcher searcher = CreateDirectorySearcher())                        {                            SearchResult searchResult = searcher.FindOne();                            if (!(searchResult is null) && searchResult.Properties.Contains("maxPwdAge"))                                maxAgePropertyValue = searchResult.Properties["maxPwdAge"][0].ToString();                        }                    }                    finally                    {                        UserInfo.EndImpersonation(currentContext);                    }                }                 if (string.IsNullOrEmpty(maxAgePropertyValue))                    return -1;                 long maxPasswordAge = long.Parse(maxAgePropertyValue);                 if (IsLocalAccount)                    return Ticks.FromSeconds(maxPasswordAge);                 return maxPasswordAge;            }        }         public string[] Groups        {            get            {            #if !MONO                if (!Enabled)                    return Array.Empty<string>();                                if (IsLocalAccount || m_useLegacyGroupLookups)                    return OldGetGroups();                 using (Logger.SuppressFirstChanceExceptionLogMessages())                {                    try                    {                        using (PrincipalContext context = IsLocalAccount ? new PrincipalContext(ContextType.Machine) : new PrincipalContext(ContextType.Domain, m_parent.Domain))                        using (UserPrincipal principal = UserPrincipal.FindByIdentity(context, m_parent.UserName))                        {                            return principal?.GetAuthorizationGroups()                                .Select(groupPrincipal => groupPrincipal.Sid.ToString())                                .Select(SIDToAccountName)                                .ToArray() ??                                  Array.Empty<string>();                        }                    }                    catch (Exception ex)                    {                        Log.Publish(MessageLevel.Error, "Get Groups", ex.Message, null, ex);                         // TODO: Fix random, inexplicable errors when looking up                        // identities via System.DirectoryServices.AccountManagement                        return OldGetGroups();                    }                }            #else                return OldGetGroups();            #endif            }        }         public string[] LocalGroups        {            get            {            #if !MONO                if (!Enabled)                    return Array.Empty<string>();                 if (IsLocalAccount || m_useLegacyGroupLookups)                    return OldGetLocalGroups();                 using (Logger.SuppressFirstChanceExceptionLogMessages())                {                    try                    {                        using (PrincipalContext context = IsLocalAccount ? new PrincipalContext(ContextType.Machine) : new PrincipalContext(ContextType.Domain, m_parent.Domain))                        using (UserPrincipal principal = UserPrincipal.FindByIdentity(context, m_parent.UserName))                        {                            return principal?.GetAuthorizationGroups()                                .Cast<GroupPrincipal>()                                .Where(groupPrincipal => groupPrincipal.GroupScope == GroupScope.Local)                                .Select(groupPrincipal => groupPrincipal.Sid.ToString())                                .Select(SIDToAccountName)                                .ToArray() ??                                 Array.Empty<string>();                        }                    }                    catch (Exception ex)                    {                        Log.Publish(MessageLevel.Error, "Get LocalGroups", ex.Message, null, ex);                         // TODO: Fix random, inexplicable errors when looking up                        // identities via System.DirectoryServices.AccountManagement                        return OldGetLocalGroups();                    }                }            #else                return OldGetLocalGroups();            #endif            }        }         public string FullLocalUserName        {            get            {                string name = GetUserPropertyValue("fullName");                 if (string.IsNullOrEmpty(name))                    name = GetUserPropertyValue("Name");                 return name;            }        }         public bool IsLocalAccount { get; private set; }         #endregion         #region [ Methods ]         /// <summary>        /// Releases all the resources used by the <see cref="WindowsUserInfo"/> object.        /// </summary>        public void Dispose()        {            Dispose(true);            GC.SuppressFinalize(this);        }         /// <summary>        /// Releases the unmanaged resources used by the <see cref="WindowsUserInfo"/> object and optionally releases the managed resources.        /// </summary>        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>        private void Dispose(bool disposing)        {            if (m_disposed)                return;             try            {                // This will be done regardless of whether the object is finalized or disposed.                if (!disposing)                    return;                 m_userEntry?.Dispose();

Lines 1–500 of 1543.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t