Remove secedit dependency (#179)
This commit is contained in:
parent
0c8f8473d5
commit
7a8933744e
|
@ -1,6 +1,7 @@
|
|||
# @manojampalam - authored initial script
|
||||
# @friism - Fixed issue with invalid SDDL on Set-Acl
|
||||
# @manojampalam - removed ntrights.exe dependency
|
||||
# @bingbing8 - removed secedit.exe dependency
|
||||
|
||||
$scriptpath = $MyInvocation.MyCommand.Path
|
||||
$scriptdir = Split-Path $scriptpath
|
||||
|
@ -10,68 +11,240 @@ $sshagentpath = Join-Path $scriptdir "ssh-agent.exe"
|
|||
$logsdir = Join-Path $scriptdir "logs"
|
||||
|
||||
$sshdAccount = "NT SERVICE\SSHD"
|
||||
$sshdSid = "S-1-5-80-3847866527-469524349-687026318-516638107-1125189541"
|
||||
|
||||
#Idea borrowed from https://gallery.technet.microsoft.com/scriptcenter/Grant-Revoke-Query-user-26e259b0
|
||||
$definition = @'
|
||||
using System;
|
||||
|
||||
namespace MyLsaWrapper
|
||||
{
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.ComponentModel;
|
||||
using System.Security.Principal;
|
||||
|
||||
using LSA_HANDLE = IntPtr;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct LSA_OBJECT_ATTRIBUTES
|
||||
{
|
||||
internal int Length;
|
||||
internal IntPtr RootDirectory;
|
||||
internal IntPtr ObjectName;
|
||||
internal int Attributes;
|
||||
internal IntPtr SecurityDescriptor;
|
||||
internal IntPtr SecurityQualityOfService;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
struct LSA_UNICODE_STRING
|
||||
{
|
||||
internal ushort Length;
|
||||
internal ushort MaximumLength;
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
internal string Buffer;
|
||||
}
|
||||
sealed class Win32Sec
|
||||
{
|
||||
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern uint LsaOpenPolicy(
|
||||
LSA_UNICODE_STRING[] SystemName,
|
||||
ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
|
||||
int AccessMask,
|
||||
out IntPtr PolicyHandle
|
||||
);
|
||||
|
||||
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern uint LsaAddAccountRights(
|
||||
LSA_HANDLE PolicyHandle,
|
||||
IntPtr pSID,
|
||||
LSA_UNICODE_STRING[] UserRights,
|
||||
int CountOfRights
|
||||
);
|
||||
|
||||
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern uint LsaRemoveAccountRights(
|
||||
LSA_HANDLE PolicyHandle,
|
||||
IntPtr pSID,
|
||||
bool AllRights,
|
||||
LSA_UNICODE_STRING[] UserRights,
|
||||
int CountOfRights
|
||||
);
|
||||
|
||||
[DllImport("advapi32")]
|
||||
internal static extern int LsaNtStatusToWinError(int NTSTATUS);
|
||||
|
||||
[DllImport("advapi32")]
|
||||
internal static extern int LsaClose(IntPtr PolicyHandle);
|
||||
}
|
||||
|
||||
internal sealed class Sid : IDisposable
|
||||
{
|
||||
public IntPtr pSid = IntPtr.Zero;
|
||||
public System.Security.Principal.SecurityIdentifier sid = null;
|
||||
|
||||
public Sid(string account)
|
||||
{
|
||||
try { sid = new SecurityIdentifier(account); }
|
||||
catch { sid = (SecurityIdentifier)(new NTAccount(account)).Translate(typeof(SecurityIdentifier)); }
|
||||
Byte[] buffer = new Byte[sid.BinaryLength];
|
||||
sid.GetBinaryForm(buffer, 0);
|
||||
|
||||
pSid = Marshal.AllocHGlobal(sid.BinaryLength);
|
||||
Marshal.Copy(buffer, 0, pSid, sid.BinaryLength);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (pSid != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(pSid);
|
||||
pSid = IntPtr.Zero;
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
~Sid() { Dispose(); }
|
||||
}
|
||||
|
||||
public sealed class LsaWrapper : IDisposable
|
||||
{
|
||||
enum Access : int
|
||||
{
|
||||
POLICY_READ = 0x20006,
|
||||
POLICY_ALL_ACCESS = 0x00F0FFF,
|
||||
POLICY_EXECUTE = 0X20801,
|
||||
POLICY_WRITE = 0X207F8
|
||||
}
|
||||
const uint STATUS_ACCESS_DENIED = 0xc0000022;
|
||||
const uint STATUS_INSUFFICIENT_RESOURCES = 0xc000009a;
|
||||
const uint STATUS_NO_MEMORY = 0xc0000017;
|
||||
const uint STATUS_OBJECT_NAME_NOT_FOUND = 0xc0000034;
|
||||
const uint STATUS_NO_MORE_ENTRIES = 0x8000001a;
|
||||
|
||||
IntPtr lsaHandle;
|
||||
|
||||
public LsaWrapper() : this(null) { } // local system if systemName is null
|
||||
public LsaWrapper(string systemName)
|
||||
{
|
||||
LSA_OBJECT_ATTRIBUTES lsaAttr;
|
||||
lsaAttr.RootDirectory = IntPtr.Zero;
|
||||
lsaAttr.ObjectName = IntPtr.Zero;
|
||||
lsaAttr.Attributes = 0;
|
||||
lsaAttr.SecurityDescriptor = IntPtr.Zero;
|
||||
lsaAttr.SecurityQualityOfService = IntPtr.Zero;
|
||||
lsaAttr.Length = Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));
|
||||
lsaHandle = IntPtr.Zero;
|
||||
LSA_UNICODE_STRING[] system = null;
|
||||
if (systemName != null)
|
||||
{
|
||||
system = new LSA_UNICODE_STRING[1];
|
||||
system[0] = InitLsaString(systemName);
|
||||
}
|
||||
|
||||
uint ret = Win32Sec.LsaOpenPolicy(system, ref lsaAttr, (int)Access.POLICY_ALL_ACCESS, out lsaHandle);
|
||||
if (ret == 0) return;
|
||||
if (ret == STATUS_ACCESS_DENIED) throw new UnauthorizedAccessException();
|
||||
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY)) throw new OutOfMemoryException();
|
||||
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
|
||||
}
|
||||
|
||||
public void AddPrivilege(string account, string privilege)
|
||||
{
|
||||
uint ret = 0;
|
||||
using (Sid sid = new Sid(account))
|
||||
{
|
||||
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
|
||||
privileges[0] = InitLsaString(privilege);
|
||||
ret = Win32Sec.LsaAddAccountRights(lsaHandle, sid.pSid, privileges, 1);
|
||||
}
|
||||
if (ret == 0) return;
|
||||
if (ret == STATUS_ACCESS_DENIED) throw new UnauthorizedAccessException();
|
||||
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY)) throw new OutOfMemoryException();
|
||||
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
|
||||
}
|
||||
|
||||
public void RemovePrivilege(string account, string privilege)
|
||||
{
|
||||
uint ret = 0;
|
||||
using (Sid sid = new Sid(account))
|
||||
{
|
||||
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
|
||||
privileges[0] = InitLsaString(privilege);
|
||||
ret = Win32Sec.LsaRemoveAccountRights(lsaHandle, sid.pSid, false, privileges, 1);
|
||||
}
|
||||
if (ret == 0) return;
|
||||
if (ret == STATUS_ACCESS_DENIED) throw new UnauthorizedAccessException();
|
||||
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY)) throw new OutOfMemoryException();
|
||||
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (lsaHandle != IntPtr.Zero)
|
||||
{
|
||||
Win32Sec.LsaClose(lsaHandle);
|
||||
lsaHandle = IntPtr.Zero;
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
~LsaWrapper() { Dispose(); }
|
||||
|
||||
// helper functions:
|
||||
static LSA_UNICODE_STRING InitLsaString(string s)
|
||||
{
|
||||
// Unicode strings max. 32KB
|
||||
if (s.Length > 0x7ffe) throw new ArgumentException("String too long");
|
||||
LSA_UNICODE_STRING lus = new LSA_UNICODE_STRING();
|
||||
lus.Buffer = s;
|
||||
lus.Length = (ushort)(s.Length * sizeof(char));
|
||||
lus.MaximumLength = (ushort)(lus.Length + sizeof(char));
|
||||
return lus;
|
||||
}
|
||||
}
|
||||
public class LsaWrapperCaller
|
||||
{
|
||||
public static void AddPrivilege(string account, string privilege)
|
||||
{
|
||||
using (LsaWrapper lsaWrapper = new LsaWrapper())
|
||||
{
|
||||
lsaWrapper.AddPrivilege(account, privilege);
|
||||
}
|
||||
}
|
||||
public static void RemovePrivilege(string account, string privilege)
|
||||
{
|
||||
using (LsaWrapper lsaWrapper = new LsaWrapper())
|
||||
{
|
||||
lsaWrapper.RemovePrivilege(account, privilege);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'@
|
||||
$references = @()
|
||||
if(($psversiontable.Containskey("psedition")) -and ($psversiontable.PSEdition -ieq "core"))
|
||||
{
|
||||
$references = "System.Security.Principal.Windows", "Microsoft.Win32.Primitives"
|
||||
}
|
||||
|
||||
try {
|
||||
$null = [MyLsaWrapper.LsaWrapperCaller]
|
||||
}
|
||||
catch {
|
||||
$types = Add-Type $definition -ref $references -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
|
||||
#Idea borrowed from http://sqldbamusings.blogspot.com/2012/03/powershell-adding-accounts-to-local.html
|
||||
function Add-Privilege
|
||||
{
|
||||
param(
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $Account,
|
||||
|
||||
[ValidateSet("SeAssignPrimaryTokenPrivilege", "SeServiceLogonRight")]
|
||||
[string] $Privilege
|
||||
)
|
||||
|
||||
#Get $Account SID
|
||||
$account_sid = $null
|
||||
try
|
||||
{
|
||||
$ntprincipal = new-object System.Security.Principal.NTAccount "$Account"
|
||||
$sid = $ntprincipal.Translate([System.Security.Principal.SecurityIdentifier])
|
||||
$account_sid = $sid.Value.ToString()
|
||||
}
|
||||
catch
|
||||
{
|
||||
Throw 'Unable to resolve '+ $Account
|
||||
}
|
||||
|
||||
#Prepare policy settings file to be applied
|
||||
$settings_to_export = [System.IO.Path]::GetTempFileName()
|
||||
"[Unicode]" | Set-Content $settings_to_export -Encoding Unicode
|
||||
"Unicode=yes" | Add-Content $settings_to_export -Force -WhatIf:$false
|
||||
"[Version]" | Add-Content $settings_to_export -Force -WhatIf:$false
|
||||
"signature=`"`$CHICAGO`$`"" | Add-Content $settings_to_export -Force -WhatIf:$false
|
||||
"Revision=1" | Add-Content $settings_to_export -Force -WhatIf:$false
|
||||
"[Privilege Rights]" | Add-Content $settings_to_export -Force -WhatIf:$false
|
||||
|
||||
#Get Current policy settings
|
||||
$imported_settings = [System.IO.Path]::GetTempFileName()
|
||||
secedit.exe /export /areas USER_RIGHTS /cfg "$($imported_settings)" > $null
|
||||
|
||||
if (-not(Test-Path $imported_settings)) {
|
||||
Throw "Unable to import current security policy settings"
|
||||
}
|
||||
|
||||
#find current assigned accounts to $Privilege and add it to $settings_to_export
|
||||
$current_settings = Get-Content $imported_settings -Encoding Unicode
|
||||
$existing_setting = $null
|
||||
foreach ($setting in $current_settings) {
|
||||
if ($setting -like "$Privilege`*") {
|
||||
$existing_setting = $setting
|
||||
}
|
||||
}
|
||||
|
||||
#Add $account_sid to list
|
||||
if ($existing_setting -eq $null) {
|
||||
$Privilege + " = *" + $account_sid | Add-Content $settings_to_export -Force -WhatIf:$false
|
||||
}
|
||||
else
|
||||
{
|
||||
$existing_setting + ",*" + $account_sid | Add-Content $settings_to_export -Force -WhatIf:$false
|
||||
}
|
||||
|
||||
#export
|
||||
secedit.exe /configure /db "secedit.sdb" /cfg "$($settings_to_export)" /areas USER_RIGHTS > $null
|
||||
|
||||
[MyLsaWrapper.LsaWrapperCaller]::AddPrivilege($Account, $Privilege)
|
||||
}
|
||||
|
||||
|
||||
|
@ -98,7 +271,7 @@ New-Service -Name sshd -BinaryPathName $sshdpath -Description "SSH Daemon" -Star
|
|||
sc.exe config sshd obj= $sshdAccount
|
||||
sc.exe privs sshd SeAssignPrimaryTokenPrivilege
|
||||
|
||||
Add-Privilege -Account $sshdAccount -Privilege SeAssignPrimaryTokenPrivilege
|
||||
Add-Privilege -Account $sshdSid -Privilege SeAssignPrimaryTokenPrivilege
|
||||
|
||||
if(-not (test-path $logsdir -PathType Container))
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue