2006 lines · 76.1 KB · C#
RawDownload
//******************************************************************************************************//  UnixUserInfo.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.////****************************************************************************************************** // Define USE_SHARED_OBJECT to use GSF.POSIX.so shared object library for unmanaged functions// Undefine USE_SHARED_OBJECT to use internally linked unmanaged functions (e.g., Mono hosted gsf service) #define USE_SHARED_OBJECT// #undef USE_SHARED_OBJECT using System;using System.Collections.Generic;using System.Diagnostics.CodeAnalysis;using System.Globalization;using System.IO;using System.Linq;using System.Runtime.InteropServices;using System.Security;using System.Security.Principal;using System.Text;using System.Threading;using GSF.Annotations;using GSF.Collections;using GSF.Configuration;using GSF.Console;using GSF.Units;using Novell.Directory.Ldap; #pragma warning disable 0649 namespace GSF.Identity{    // Unix implementation of key UserInfo class elements    internal sealed class UnixUserInfo : IUserInfo    {        #region [ Members ]         // Nested Types         // ReSharper disable UnusedMember.Local        [Serializable]        private class UnixIdentity : WindowsIdentity        {            #region [ Members ]             // Fields            private readonly string m_domain;            private readonly string m_userName;            private LdapConnection m_connection;            private string m_providerType;            private string m_ldapRoot;            private readonly bool m_loadedUserPasswordInformation;            private readonly UserPasswordInformation m_userPasswordInformation;            private readonly AccountStatus m_accountStatus;             #endregion             #region [ Constructors ]             public UnixIdentity(string domain, string userName, LdapConnection connection = null)                : base(GetUserIDAsToken(domain, userName), null, WindowsAccountType.Normal, true)            {                m_domain = domain;                m_userName = userName;                Connection = connection;                 if (UserInfo.IsLocalDomain(domain))                {                    // Cache shadow information for local user before possible reduction in privileges                    if (GetLocalUserPasswordInformation(userName, out m_userPasswordInformation, out m_accountStatus) == 0)                        m_loadedUserPasswordInformation = true;                    else                        m_accountStatus = AccountStatus.Disabled;                }            }             #endregion             #region [ Properties ]             public string Domain            {                get                {                    return m_domain;                }            }             public string UserName            {                get                {                    return m_userName;                }            }             public string LoginID            {                get                {                    return string.Format("{0}\\{1}", m_domain, m_userName);                }            }             public string ProviderType            {                get                {                    return m_providerType;                }            }             public string LdapRoot            {                get                {                    return m_ldapRoot;                }            }             public LdapConnection Connection            {                get                {                    return m_connection;                }                set                {                    m_connection = value;                    m_providerType = (object)m_connection == null ? "PAM_LOCAL" : "PAM_LDAP";                     if ((object)m_connection != null)                    {                        // Extract LDAP search root distinguished name                        StringBuilder ldapRoot = new StringBuilder();                        string[] elements = m_connection.GetSchemaDN().Split(',');                         for (int i = 0; i < elements.Length; i++)                        {                            string element = elements[i].Trim();                             if (element.StartsWith("DC", StringComparison.OrdinalIgnoreCase))                            {                                if (ldapRoot.Length > 0)                                    ldapRoot.Append(',');                                 ldapRoot.Append(element);                            }                        }                         m_ldapRoot = ldapRoot.ToString();                    }                    else                    {                        m_ldapRoot = "";                    }                }            }             public bool LoadedUserPasswordInformation            {                get                {                    return m_loadedUserPasswordInformation;                }            }             public UserPasswordInformation UserPasswordInformation            {                get                {                    return m_userPasswordInformation;                }            }             public AccountStatus AccountStatus            {                get                {                    return m_accountStatus;                }            }             #endregion             #region [ Static ]             private static IntPtr GetUserIDAsToken(string domain, string userName)            {                uint userID;                 if (!UserInfo.IsLocalDomain(domain))                    userName = string.Format("{0}\\{1}", domain, userName);                 return GetLocalUserID(userName, out userID) == 0 ? new IntPtr(userID) : IntPtr.Zero;            }             #endregion        }         private struct UserPasswordInformation        {            [UsedImplicitly]            public long lastChangeDate;            [UsedImplicitly]            public long minDaysForChange;            [UsedImplicitly]            public long maxDaysForChange;            [UsedImplicitly]            public long warningDays;            [UsedImplicitly]            public long inactivityDays;            [UsedImplicitly]            public long accountExpirationDate;        }         private struct UserPasswordInformation32        {            [UsedImplicitly]            public int lastChangeDate;            [UsedImplicitly]            public int minDaysForChange;            [UsedImplicitly]            public int maxDaysForChange;            [UsedImplicitly]            public int warningDays;            [UsedImplicitly]            public int inactivityDays;            [UsedImplicitly]            public int accountExpirationDate;        }         private enum AccountStatus        {            [UsedImplicitly]            Normal,     // 0: Normal - encrypted password            [UsedImplicitly]            Disabled,   // 1: Password is *            [UsedImplicitly]            LockedOut,  // 2: Password starts with !            [UsedImplicitly]            NoPassword  // 3: Password is not defined (blank)        }         private enum PAMResponseCode        {            PAM_SYSTEM_ERR = 4,            PAM_BUF_ERR = 5,            PAM_PERM_DENIED = 7,            PAM_MAXTRIES = 8,            PAM_AUTH_ERR = 9,            PAM_CRED_INSUFFICIENT = 11,            PAM_AUTHINFO_UNAVAIL = 12,            PAM_USER_UNKNOWN = 13,            PAM_AUTHTOK_ERR = 20,            PAM_AUTHTOK_RECOVERY_ERR = 21,            PAM_AUTHTOK_LOCK_BUSY = 22,            PAM_AUTHTOK_DISABLE_AGING = 23,            PAM_ABORT = 26,            PAM_TRY_AGAIN = 27        }         // Constants        private const int MaxAccountNameLength = 256;         // DllImport code is in GSF.POSIX.c#if USE_SHARED_OBJECT        private const string ImportFileName = "./GSF.POSIX.so";#else        private const string ImportFileName = "__Internal";#endif         // Fields        private readonly UserInfo m_parent;        private LdapConnection m_connection;        private LdapEntry m_userEntry;        private string m_ldapRoot;        private bool m_domainRespondsForUser;        private bool m_isLocalAccount;        private bool m_enabled;        private bool m_initialized;        private bool m_disposed;         #endregion         #region [ Constructors ]         public UnixUserInfo(UserInfo parent)        {            m_parent = parent;        }         ~UnixUserInfo()        {            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 =                            (object)identity != null &&                            !string.IsNullOrEmpty(m_parent.LoginID) &&                            identity.Name.Equals(m_parent.LoginID, StringComparison.OrdinalIgnoreCase) &&                            identity.IsAuthenticated;                    }                }                 if (!exists)                {                    if (IsLocalAccount)                    {                        try                        {                            exists = LocalUserExists(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            {                DateTime lastLogon = DateTime.MinValue;                 if (m_enabled)                {                    try                    {                        CommandResponse response = Command.Execute("lastlog", "-u " + EncodeAccountName(m_isLocalAccount ? m_parent.UserName : m_parent.LoginID));                         if (response.ExitCode == 0)                        {                            string[] lines = response.StandardOutput.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);                             if (lines.Length < 2 || lines[1].Length < 44 || !DateTime.TryParseExact(lines[1].Substring(43), "ddd MMM d HH:mm:ss zzff yyyy", CultureInfo.InvariantCulture, DateTimeStyles.AllowInnerWhite, out lastLogon))                                lastLogon = DateTime.MinValue;                        }                        else                        {                            if (!m_isLocalAccount)                                lastLogon = DateTime.FromFileTime(long.Parse(GetUserPropertyValue("lastLogon")));                        }                    }                    catch                    {                        lastLogon = DateTime.MinValue;                    }                }                 return lastLogon;            }        }         public DateTime AccountCreationDate        {            get            {                DateTime creationDate = DateTime.MinValue;                 if (m_enabled)                {                    try                    {                        creationDate = Directory.GetCreationTime(Environment.GetEnvironmentVariable("HOME") ?? EncodeAccountName("/home/" + m_parent.UserName));                    }                    catch                    {                        if (!m_isLocalAccount || !DateTime.TryParseExact(GetUserPropertyValue("whenCreated"), "yyyyMMddHHmmss.fZ", CultureInfo.InvariantCulture, DateTimeStyles.AllowInnerWhite | DateTimeStyles.AssumeUniversal, out creationDate))                            creationDate = DateTime.MinValue;                    }                }                 return creationDate;            }        }         public DateTime NextPasswordChangeDate        {            get            {                DateTime passwordChangeDate = DateTime.MaxValue;                 if (m_enabled)                {                    if (IsLocalAccount)                    {                        UserPasswordInformation userPasswordInfo;                        AccountStatus status;                         if (GetCachedLocalUserPasswordInformation(m_parent.PassthroughPrincipal, m_isLocalAccount ? m_parent.UserName : m_parent.LoginID, out userPasswordInfo, out status) == 0)                        {                            if (userPasswordInfo.maxDaysForChange >= 99999)                            {                                passwordChangeDate = DateTime.MaxValue;                            }                            else                            {                                // From chage.c source:                                //   The password expiration date is determined from the last change                                //   date plus the number of days the password is valid for.                                UnixTimeTag expirationDate = new UnixTimeTag((uint)(userPasswordInfo.lastChangeDate + userPasswordInfo.maxDaysForChange));                                passwordChangeDate = expirationDate.ToDateTime();                            }                        }                    }                    else                    {                        try                        {                            long passwordSetOn = long.Parse(GetUserPropertyValue("pwdLastSet"));                             if (passwordSetOn == 0)                            {

Lines 1–500 of 2006.

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