// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

//using System.Management.Automation.SecurityAccountsManager.Native;

namespace System.Management.Automation.SecurityAccountsManager.Native.NtSam
{
    #region Enums
    internal enum ALIAS_INFORMATION_CLASS
    {
        AliasGeneralInformation = 1,
        AliasNameInformation,
        AliasAdminCommentInformation,
        AliasReplicationInformation,
        AliasExtendedInformation,
    }

    internal enum GROUP_INFORMATION_CLASS
    {
        GroupGeneralInformation = 1,
        GroupNameInformation,
        GroupAttributeInformation,
        GroupAdminCommentInformation,
        GroupReplicationInformation
    }

    internal enum USER_INFORMATION_CLASS
    {
        UserGeneralInformation      = 1,
        UserPreferencesInformation,
        UserLogonInformation,
        UserLogonHoursInformation,
        UserAccountInformation,
        UserNameInformation,
        UserAccountNameInformation,
        UserFullNameInformation,
        UserPrimaryGroupInformation,
        UserHomeInformation,
        UserScriptInformation,
        UserProfileInformation,
        UserAdminCommentInformation,
        UserWorkStationsInformation,
        UserSetPasswordInformation,
        UserControlInformation,
        UserExpiresInformation,
        UserInternal1Information,
        UserInternal2Information,
        UserParametersInformation,
        UserAllInformation,
        UserInternal3Information,
        UserInternal4Information,
        UserInternal5Information,
        UserInternal4InformationNew,
        UserInternal5InformationNew,
        UserInternal6Information,
        UserExtendedInformation,
        UserLogonUIInformation,
    }

    #endregion Enums

    #region Structures
    [StructLayout(LayoutKind.Sequential)]
    internal struct SR_SECURITY_DESCRIPTOR
    {
        public UInt32 Length;
        public IntPtr SecurityDescriptor;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct LOGON_HOURS
    {
        public UInt16 UnitsPerWeek;

        //
        // UnitsPerWeek is the number of equal length time units the week is
        // divided into.  This value is used to compute the length of the bit
        // string in logon_hours.  Must be less than or equal to
        // SAM_UNITS_PER_WEEK (10080) for this release.
        //
        // LogonHours is a bit map of valid logon times.  Each bit represents
        // a unique division in a week.  The largest bit map supported is 1260
        // bytes (10080 bits), which represents minutes per week.  In this case
        // the first bit (bit 0, byte 0) is Sunday, 00:00:00 - 00-00:59; bit 1,
        // byte 0 is Sunday, 00:01:00 - 00:01:59, etc.  A NULL pointer means
        // DONT_CHANGE for SamSetInformationUser() calls.
        //

        public IntPtr LogonHours;
    }

    [StructLayout(LayoutKind.Sequential, Pack=4)]
    internal struct USER_ALL_INFORMATION
    {
        public LARGE_INTEGER LastLogon;
        public LARGE_INTEGER LastLogoff;
        public LARGE_INTEGER PasswordLastSet;
        public LARGE_INTEGER AccountExpires;
        public LARGE_INTEGER PasswordCanChange;
        public LARGE_INTEGER PasswordMustChange;
        public UNICODE_STRING UserName;
        public UNICODE_STRING FullName;
        public UNICODE_STRING HomeDirectory;
        public UNICODE_STRING HomeDirectoryDrive;
        public UNICODE_STRING ScriptPath;
        public UNICODE_STRING ProfilePath;
        public UNICODE_STRING AdminComment;
        public UNICODE_STRING WorkStations;
        public UNICODE_STRING UserComment;
        public UNICODE_STRING Parameters;
        public UNICODE_STRING LmPassword;
        public UNICODE_STRING NtPassword;
        public UNICODE_STRING PrivateData;
        public SR_SECURITY_DESCRIPTOR SecurityDescriptor;
        public UInt32 UserId;
        public UInt32 PrimaryGroupId;
        public UInt32 UserAccountControl;
        public UInt32 WhichFields;
        public LOGON_HOURS LogonHours;
        public UInt16 BadPasswordCount;
        public UInt16 LogonCount;
        public UInt16 CountryCode;
        public UInt16 CodePage;
        [MarshalAs(UnmanagedType.I1)]
        public bool LmPasswordPresent;
        [MarshalAs(UnmanagedType.I1)]
        public bool NtPasswordPresent;
        [MarshalAs(UnmanagedType.I1)]
        public bool PasswordExpired;
        [MarshalAs(UnmanagedType.I1)]
        public bool PrivateDataSensitive;
    }

    [StructLayout(LayoutKind.Sequential, Pack=4)]
    internal struct USER_GENERAL_INFORMATION
    {
        public UNICODE_STRING UserName;
        public UNICODE_STRING FullName;
        public UInt32 PrimaryGroupId;
        public UNICODE_STRING AdminComment;
        public UNICODE_STRING UserComment;
    }

    [StructLayout(LayoutKind.Sequential, Pack=4)]
    internal struct USER_LOGON_INFORMATION
    {
        public UNICODE_STRING UserName;
        public UNICODE_STRING FullName;
        public UInt32 UserId;
        public UInt32 PrimaryGroupId;
        public UNICODE_STRING HomeDirectory;
        public UNICODE_STRING HomeDirectoryDrive;
        public UNICODE_STRING ScriptPath;
        public UNICODE_STRING ProfilePath;
        public UNICODE_STRING WorkStations;
        public LARGE_INTEGER LastLogon;
        public LARGE_INTEGER LastLogoff;
        public LARGE_INTEGER PasswordLastSet;
        public LARGE_INTEGER PasswordCanChange;
        public LARGE_INTEGER PasswordMustChange;
        public LOGON_HOURS LogonHours;
        public UInt16 BadPasswordCount;
        public UInt16 LogonCount;
        public UInt32 UserAccountControl;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct USER_ACCOUNT_NAME_INFORMATION
    {
        public UNICODE_STRING UserName;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct USER_FULL_NAME_INFORMATION
    {
        public UNICODE_STRING FullName;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct USER_NAME_INFORMATION
    {
        public UNICODE_STRING UserName;
        public UNICODE_STRING FullName;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct USER_ADMIN_COMMENT_INFORMATION
    {
        UNICODE_STRING AdminComment;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct USER_EXPIRES_INFORMATION
    {
        // LARGE_INTEGER AccountExpires;
        public Int64 AccountExpires;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct USER_SET_PASSWORD_INFORMATION
    {
        public UNICODE_STRING Password;
        public bool PasswordExpired;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct USER_LOGON_HOURS_INFORMATION
    {
        public LOGON_HOURS LogonHours;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct POLICY_PRIMARY_DOMAIN_INFO
    {
        public UNICODE_STRING Name;
        public IntPtr Sid;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct ALIAS_GENERAL_INFORMATION
    {
        public UNICODE_STRING Name;
        public UInt32 MemberCount;
        public UNICODE_STRING AdminComment;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct ALIAS_NAME_INFORMATION
    {
        public UNICODE_STRING Name;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct ALIAS_ADM_COMMENT_INFORMATION
    {
        public UNICODE_STRING AdminComment;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct SAMPR_GROUP_GENERAL_INFORMATION
    {
        public UNICODE_STRING Name;
        public UInt32 Attributes;
        public UInt32 MemberCount;
        public UNICODE_STRING AdminComment;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct SAMPR_GROUP_NAME_INFORMATION
    {
        public UNICODE_STRING Name;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct SAM_RID_ENUMERATION
    {
        public UInt32 RelativeId;
        public UNICODE_STRING Name;
    }
    #endregion Structures

    /// <summary>
    /// Provides methods for invoking functions in the Windows
    /// Security Accounts Manager (SAM) API.
    /// </summary>
    internal static class SamApi
    {
        #region Constants
        // Account enumeration filters, may be combined by bitwise OR
        internal const UInt32 SAM_USER_ENUMERATION_FILTER_LOCAL     = 0x00000001;
        internal const UInt32 SAM_USER_ENUMERATION_FILTER_INTERNET  = 0x00000002;
        internal const UInt32 SAM_SERVER_LOOKUP_DOMAIN              = 0x0020;

        //
        // Bits to be used in UserAllInformation's WhichFields field (to indicate
        // which items were queried or set).
        //
        internal const UInt32 USER_ALL_USERNAME             = 0x00000001;
        internal const UInt32 USER_ALL_FULLNAME             = 0x00000002;
        internal const UInt32 USER_ALL_USERID               = 0x00000004;
        internal const UInt32 USER_ALL_PRIMARYGROUPID       = 0x00000008;
        internal const UInt32 USER_ALL_ADMINCOMMENT         = 0x00000010;
        internal const UInt32 USER_ALL_USERCOMMENT          = 0x00000020;
        internal const UInt32 USER_ALL_HOMEDIRECTORY        = 0x00000040;
        internal const UInt32 USER_ALL_HOMEDIRECTORYDRIVE   = 0x00000080;
        internal const UInt32 USER_ALL_SCRIPTPATH           = 0x00000100;
        internal const UInt32 USER_ALL_PROFILEPATH          = 0x00000200;
        internal const UInt32 USER_ALL_WORKSTATIONS         = 0x00000400;
        internal const UInt32 USER_ALL_LASTLOGON            = 0x00000800;
        internal const UInt32 USER_ALL_LASTLOGOFF           = 0x00001000;
        internal const UInt32 USER_ALL_LOGONHOURS           = 0x00002000;
        internal const UInt32 USER_ALL_BADPASSWORDCOUNT     = 0x00004000;
        internal const UInt32 USER_ALL_LOGONCOUNT           = 0x00008000;
        internal const UInt32 USER_ALL_PASSWORDCANCHANGE    = 0x00010000;
        internal const UInt32 USER_ALL_PASSWORDMUSTCHANGE   = 0x00020000;
        internal const UInt32 USER_ALL_PASSWORDLASTSET      = 0x00040000;
        internal const UInt32 USER_ALL_ACCOUNTEXPIRES       = 0x00080000;
        internal const UInt32 USER_ALL_USERACCOUNTCONTROL   = 0x00100000;
        internal const UInt32 USER_ALL_PARAMETERS           = 0x00200000;   // ntsubauth
        internal const UInt32 USER_ALL_COUNTRYCODE          = 0x00400000;
        internal const UInt32 USER_ALL_CODEPAGE             = 0x00800000;
        internal const UInt32 USER_ALL_NTPASSWORDPRESENT    = 0x01000000;   // field AND boolean
        internal const UInt32 USER_ALL_LMPASSWORDPRESENT    = 0x02000000;   // field AND boolean
        internal const UInt32 USER_ALL_PRIVATEDATA          = 0x04000000;   // field AND boolean
        internal const UInt32 USER_ALL_PASSWORDEXPIRED      = 0x08000000;
        internal const UInt32 USER_ALL_SECURITYDESCRIPTOR   = 0x10000000;
        internal const UInt32 USER_ALL_OWFPASSWORD          = 0x20000000;   // boolean

        internal const UInt32 USER_ALL_UNDEFINED_MASK       = 0xC0000000;

        //
        // Bit masks for the UserAccountControl member of the USER_ALL_INFORMATION structure
        //
        internal const UInt32 USER_ACCOUNT_DISABLED                       = 0x00000001;
        internal const UInt32 USER_HOME_DIRECTORY_REQUIRED                = 0x00000002;
        internal const UInt32 USER_PASSWORD_NOT_REQUIRED                  = 0x00000004;
        internal const UInt32 USER_TEMP_DUPLICATE_ACCOUNT                 = 0x00000008;
        internal const UInt32 USER_NORMAL_ACCOUNT                         = 0x00000010;
        internal const UInt32 USER_MNS_LOGON_ACCOUNT                      = 0x00000020;
        internal const UInt32 USER_INTERDOMAIN_TRUST_ACCOUNT              = 0x00000040;
        internal const UInt32 USER_WORKSTATION_TRUST_ACCOUNT              = 0x00000080;
        internal const UInt32 USER_SERVER_TRUST_ACCOUNT                   = 0x00000100;
        internal const UInt32 USER_DONT_EXPIRE_PASSWORD                   = 0x00000200;
        internal const UInt32 USER_ACCOUNT_AUTO_LOCKED                    = 0x00000400;
        internal const UInt32 USER_ENCRYPTED_TEXT_PASSWORD_ALLOWED        = 0x00000800;
        internal const UInt32 USER_SMARTCARD_REQUIRED                     = 0x00001000;
        internal const UInt32 USER_TRUSTED_FOR_DELEGATION                 = 0x00002000;
        internal const UInt32 USER_NOT_DELEGATED                          = 0x00004000;
        internal const UInt32 USER_USE_DES_KEY_ONLY                       = 0x00008000;
        internal const UInt32 USER_DONT_REQUIRE_PREAUTH                   = 0x00010000;
        internal const UInt32 USER_PASSWORD_EXPIRED                       = 0x00020000;
        internal const UInt32 USER_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0x00040000;
        internal const UInt32 USER_NO_AUTH_DATA_REQUIRED                  = 0x00080000;
        internal const UInt32 USER_PARTIAL_SECRETS_ACCOUNT                = 0x00100000;
        internal const UInt32 USER_USE_AES_KEYS                           = 0x00200000;

        //
        // Access rights for user object
        //
        internal const UInt16 USER_CHANGE_PASSWORD  = 0x0040;
        #endregion Constants

        #region Sam Functions
        [DllImport("samlib.dll")]
        public static extern UInt32 SamConnect(ref UNICODE_STRING serverName,
                                               out IntPtr serverHandle,
                                               UInt32 desiredAccess,
                                               ref OBJECT_ATTRIBUTES objectAttributes);

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamRidToSid(IntPtr objectHandle, UInt32 rid, out IntPtr sid);

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamCloseHandle(IntPtr serverHandle);

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamFreeMemory(IntPtr buffer);

        #region Domain Functions
        [DllImport("samlib.dll")]
        internal static extern UInt32 SamOpenDomain(IntPtr serverHandle,
                                                    UInt32 desiredAccess,
                                                    IntPtr domainId,
                                                    out IntPtr domainHandle);
        #endregion Domain Functions

        #region Alias Functions
        [DllImport("samlib.dll")]
        internal static extern UInt32 SamEnumerateAliasesInDomain(IntPtr domainHandle,
                                                                  ref UInt32 enumerationContext,
                                                                  out IntPtr buffer,
                                                                  UInt32 preferredMaximumLength,
                                                                  out UInt32 countReturned);

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamCreateAliasInDomain(IntPtr domainHandle,
                                                             IntPtr accountName,        // PUNICODE_STRING
                                                             UInt32 desiredAccess,
                                                             out IntPtr aliasHandle,
                                                             out UInt32 relativeId);    // PULONG

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamOpenAlias(IntPtr domainHandle,
                                                   UInt32 desiredAccess,
                                                   UInt32 aliasId,
                                                   out IntPtr aliasHandle);

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamQueryInformationAlias(IntPtr aliasHandle,
                                                               ALIAS_INFORMATION_CLASS aliasInformationClass,
                                                               out IntPtr buffer);

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamSetInformationAlias(IntPtr aliasHandle,
                                                             ALIAS_INFORMATION_CLASS aliasInformationClass,
                                                             IntPtr buffer);

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamDeleteAlias(IntPtr aliasHandle);

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamAddMemberToAlias(IntPtr aliasHandle,
                                                          byte[] memberId);     // PSID

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamRemoveMemberFromAlias(IntPtr aliasHandle,
                                                               byte[] memberId);    // PSID

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamGetMembersInAlias(IntPtr aliasHandle,
                                                           out IntPtr memberIds,    // PSID **
                                                           out UInt32 memberCount);
        #endregion Alias Functions

        #region User Functions
        [DllImport("samlib.dll")]
        internal static extern UInt32 SamOpenUser(IntPtr domainHandle,
                                                  UInt32 desiredAccess,
                                                  UInt32 userID,
                                                  out IntPtr userHandle);

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamDeleteUser(IntPtr aliasHandle);

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamEnumerateUsersInDomain(IntPtr domainHandle,
                                                                ref UInt32 enumerationContext,
                                                                UInt32 userAccountControl,
                                                                out IntPtr buffer,
                                                                UInt32 preferredMaximumLength,
                                                                out UInt32 countReturned);

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamCreateUser2InDomain(IntPtr domainHandle,
                                                             ref UNICODE_STRING accountName,
                                                             Int32 accountType,
                                                             UInt32 desiredAccess,
                                                             out IntPtr userHandle,
                                                             out UInt32 grantedAccess,
                                                             out UInt32 relativeId);

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamQueryInformationUser(IntPtr userHandle,
                                                              USER_INFORMATION_CLASS userInformationClass,
                                                              out IntPtr buffer);

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamSetInformationUser(IntPtr userHandle,
                                                            USER_INFORMATION_CLASS userInformationClass,
                                                            IntPtr buffer);

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamQuerySecurityObject(IntPtr objectHandle,
                                                             UInt32 securityInformation,
                                                             out IntPtr securityDescriptor);

        [DllImport("samlib.dll")]
        internal static extern UInt32 SamSetSecurityObject(IntPtr objectHandle,
                                                           UInt32 SecurityInformation,
                                                           IntPtr SecurityDescriptor);
        #endregion User Functions
        #endregion Sam Functions
    }
}
