1513 lines · 61.6 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.Interop;using GSF.IO;using Microsoft.Win32; namespace 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 bool m_isLocalAccount;        private bool m_enabled;        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.            }        }         ~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...                        WindowsPrincipal windowsPrincipal = Thread.CurrentPrincipal as WindowsPrincipal;                         exists =                            (object)windowsPrincipal != null &&                            !string.IsNullOrEmpty(m_parent.LoginID) &&                            windowsPrincipal.Identity.Name.Equals(m_parent.LoginID, StringComparison.OrdinalIgnoreCase) &&                            windowsPrincipal.Identity.IsAuthenticated;                    }                }                 if (!exists)                {                    if (m_isLocalAccount)                    {                        try                        {                            exists = DirectoryEntry.Exists("WinNT://" + m_parent.Domain + "/" + m_parent.UserName);                        }                        catch                        {                            exists = false;                        }                    }                    else                    {                        exists = ((object)m_userEntry != null);                    }                }                 return exists;            }        }         public bool Enabled        {            get            {                return m_enabled;            }            set            {                m_enabled = value;            }        }         public DateTime LastLogon        {            get            {                if (m_enabled)                {                    try                    {                        if (m_isLocalAccount)                            return DateTime.Parse(GetUserPropertyValue("lastLogin"));                         return DateTime.FromFileTime(ConvertToLong(GetUserPropertyValueCollection("lastLogon").Value));                    }                    catch                    {                        return DateTime.MinValue;                    }                }                 return DateTime.MinValue;            }        }         public DateTime AccountCreationDate        {            get            {                if (m_enabled)                {                    try                    {                        if (m_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 (m_enabled && !m_parent.PasswordCannotChange && !m_parent.PasswordDoesNotExpire)                {                    try                    {                        if (m_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;                string userPropertyValue;                 if (m_enabled && m_isLocalAccount)                {                    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 (m_enabled)                {                    string maxAgePropertyValue = string.Empty;                     if (m_isLocalAccount)                    {                        maxAgePropertyValue = GetUserPropertyValue("maxPasswordAge");                    }                    else                    {                        WindowsImpersonationContext currentContext = null;                        try                        {                            currentContext = m_parent.ImpersonatePrivilegedAccount();                            using (DirectorySearcher searcher = CreateDirectorySearcher())                            {                                SearchResult searchResult = searcher.FindOne();                                if ((object)searchResult != 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 (m_isLocalAccount)                        return Ticks.FromSeconds(maxPasswordAge);                     return maxPasswordAge;                }                 return -1;            }        }         public string[] Groups        {            get            {                HashSet<string> groups = new HashSet<string>(StringComparer.OrdinalIgnoreCase);                string groupName;                 if (m_enabled)                {                    if (m_isLocalAccount)                    {                        // Get fixed list of BUILTIN local groups                        string[] builtInGroups = UserInfo.GetBuiltInLocalGroups();                         // Get local groups that local user is a member of                        object localGroups = m_userEntry.Invoke("Groups");                         foreach (object localGroup in (IEnumerable)localGroups)                        {                            using (DirectoryEntry groupEntry = new DirectoryEntry(localGroup))                            {                                groupName = groupEntry.Name;                                 if (Array.BinarySearch(builtInGroups, groupName, StringComparer.OrdinalIgnoreCase) < 0)                                    groups.Add(Environment.MachineName + "\\" + groupName);                                else                                    groups.Add("BUILTIN\\" + groupName);                            }                        }                         // Union this with a manual scan of local groups since "Groups" call will not derive                        // "NT AUTHORITY\Authenticated Users" which will miss "BUILTIN\Users" for authenticated                        // users. This will also catch other groups that may have been missed by "Groups" call.                        groups.UnionWith(LocalGroups);                    }                    else                    {                        // Get active directory groups that active directory user is a member of                        m_userEntry.RefreshCache(new[] { "TokenGroups" });                         foreach (byte[] sid in m_userEntry.Properties["TokenGroups"])                        {                            try                            {                                groupName = new SecurityIdentifier(sid, 0).Translate(typeof(NTAccount)).ToString();                                groups.Add(groupName);                            }                            catch (IdentityNotMappedException)                            {                                // This might happen when AD server is not accessible.                            }                            catch (SystemException)                            {                                // Ignoring group SID's that fail to translate to an active AD group, for whatever reason                            }                        }                         // Union this with local groups that active directory user is a member of. The                        // "TokenGroups" call doesn't get all of these :-p, generally this call only                        // returns some of the common "BUILTIN\*" groups.                        groups.UnionWith(LocalGroups);                    }                }                 return groups.ToArray();            }        }         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]        public string[] LocalGroups        {            get            {                List<string> groups = new List<string>();                const string authenticatedUsersGroupPath = "WinNT://NT AUTHORITY/Authenticated Users";                 // Get local groups that user is a member of                DirectoryEntry root = new DirectoryEntry("WinNT://.,computer", null, null, AuthenticationTypes.Secure);                string userPath = string.Format("WinNT://{0}/{1}", m_parent.Domain, m_parent.UserName);                string groupName;                bool userIsAuthenticated = false;                 string[] builtInGroups = UserInfo.GetBuiltInLocalGroups();                 // See if identity for current thread matches user information login ID - when this is true we can check                 // if the current user is authenticated. When a user is authenticated we will also need to validate if                // the local groups that contain the local "NT AUTHORITY\Authenticated Users" group.                if (Thread.CurrentPrincipal.Identity.Name.Equals(m_parent.LoginID, StringComparison.OrdinalIgnoreCase))                    userIsAuthenticated = Thread.CurrentPrincipal.Identity.IsAuthenticated;                 // Only enumerate groups                root.Children.SchemaFilter.Add("Group");                 // Have to scan each local group for the AD user...                foreach (DirectoryEntry groupEntry in root.Children)                {                    if ((bool)groupEntry.Invoke("IsMember", new object[] { userPath }) ||                        (userIsAuthenticated && (bool)groupEntry.Invoke("IsMember", new object[] { authenticatedUsersGroupPath })))                    {                        groupName = groupEntry.Name;                         if (Array.BinarySearch(builtInGroups, groupName, StringComparer.OrdinalIgnoreCase) < 0)                            groups.Add(Environment.MachineName + "\\" + groupName);                        else                            groups.Add("BUILTIN\\" + groupName);                    }                }                 return groups.ToArray();            }        }         public string FullLocalUserName        {            get            {                string name = GetUserPropertyValue("fullName");                 if (string.IsNullOrEmpty(name))                    name = GetUserPropertyValue("Name");                 return name;            }        }         public bool IsLocalAccount        {            get            {                return m_isLocalAccount;            }        } 

Lines 1–500 of 1513.

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