Thursday, December 22, 2011

Check Credentials in local Security Policy

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace LsaSecurity
{
/*
* LsaWrapper class credit: Willy Denoyette [MVP]
*
* http://www.hightechtalks.com/csharp/lsa-functions-276626.html
*
* Added support for:
*
* LsaLookupSids
*
* for the purposes of providing a working example.
*
*
*
*/


using System.Runtime.InteropServices;
using System.Security;
using System.Management;
using System.Runtime.CompilerServices;
using System.ComponentModel;

using LSA_HANDLE = IntPtr;

public class Program
{
public static void Main()
{
using (LsaWrapper lsaSec = new LsaWrapper())
{
//// string[] accounts = lsaSec.GetUsersWithPrivilege("SeNetworkLogonRight");
ArrayList accounts = lsaSec.GetUsersWithPrivilege("SeDenyBatchLogonRight");//SeServiceLogonRight //SeCreateGlobalPrivilege//SeDenyBatchLogonRight
//int returnvalue = lsaSec.checkUserRights("AMAT\\KYADAV106192");
}


}
}

[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),
SuppressUnmanagedCodeSecurityAttribute]
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),
SuppressUnmanagedCodeSecurityAttribute]
internal static extern uint LsaAddAccountRights(
LSA_HANDLE PolicyHandle,
IntPtr pSID,
LSA_UNICODE_STRING[] UserRights,
int CountOfRights
);

[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
SuppressUnmanagedCodeSecurityAttribute]
internal static extern uint LsaRemoveAccountRights(
LSA_HANDLE PolicyHandle,
IntPtr pSID,
bool allRights,
LSA_UNICODE_STRING[] UserRights,
int CountOfRights
);

[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
SuppressUnmanagedCodeSecurityAttribute]
internal static extern uint LsaEnumerateAccountsWithUserRight(
LSA_HANDLE PolicyHandle,
LSA_UNICODE_STRING[] UserRights,
out IntPtr EnumerationBuffer,
out int CountReturned
);

[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
SuppressUnmanagedCodeSecurityAttribute]
internal static extern uint LsaLookupSids(
LSA_HANDLE PolicyHandle,
int count,
IntPtr buffer,
[MarshalAs(UnmanagedType.SysInt)] out LSA_HANDLE domainList,
out LSA_HANDLE nameList
);

// NTSTATUS LsaLookupSids2(
// _In_ LSA_HANDLE PolicyHandle,
// _In_ ULONG LookupOptions,
// _In_ ULONG Count,
// _In_ PSID *Sids,
// _Out_ PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains,
// _Out_ PLSA_TRANSLATED_NAME *Names
//);
[DllImport("Advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
internal static extern uint LsaLookupSids2(
LSA_HANDLE PolicyHandle,
int LookupOptions,
int Count,
IntPtr buffer,
out LSA_HANDLE domainList,
out LSA_HANDLE nameList
);

[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
SuppressUnmanagedCodeSecurityAttribute]
internal static extern int LsaLookupNames2(
LSA_HANDLE PolicyHandle,
uint Flags,
uint Count,
LSA_UNICODE_STRING[] Names,
ref IntPtr ReferencedDomains,
ref IntPtr Sids
);

[DllImport("advapi32")]
internal static extern int LsaNtStatusToWinError(int NTSTATUS);

[DllImport("advapi32")]
internal static extern int LsaClose(IntPtr PolicyHandle);

[DllImport("advapi32")]
internal static extern int LsaFreeMemory(IntPtr Buffer);

}

public sealed class LsaWrapper : IDisposable
{
private bool _writeToConsole = false;

[StructLayout(LayoutKind.Sequential)]
struct LSA_TRUST_INFORMATION
{
internal LSA_UNICODE_STRING Name;
internal IntPtr Sid;
}
[StructLayout(LayoutKind.Sequential)]
struct LSA_TRANSLATED_SID2
{
internal SidNameUse Use;
internal IntPtr Sid;
internal int DomainIndex;
uint Flags;
}

//[StructLayout(LayoutKind.Sequential)]
//struct LSA_REFERENCED_DOMAIN_LIST
//{
// internal uint Entries;
// internal LSA_TRUST_INFORMATION Domains;
//}

[StructLayout(LayoutKind.Sequential)]
internal struct LSA_REFERENCED_DOMAIN_LIST
{
internal uint Entries;
internal IntPtr Domains;
}

[StructLayout(LayoutKind.Sequential)]
struct LSA_ENUMERATION_INFORMATION
{
internal LSA_HANDLE PSid;
}

[StructLayout(LayoutKind.Sequential)]
struct LSA_SID
{
internal uint Sid;
}

[StructLayout(LayoutKind.Sequential)]
struct LSA_TRANSLATED_NAME
{
internal SidNameUse Use;
internal LSA_UNICODE_STRING Name;
internal int DomainIndex;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct LOCALGROUP_USERS_INFO_0
{
public string groupname;
}

enum SidNameUse : int
{
User = 1,
Group = 2,
Domain = 3,
Alias = 4,
KnownGroup = 5,
DeletedAccount = 6,
Invalid = 7,
Unknown = 8,
Computer = 9
}

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;

IntPtr lsaHandle;

public LsaWrapper()
: this(null)
{ }
// // local system if systemName is null
public int checkUserRights(string Username)
{
ArrayList accountsLogOnAsBatch;
ArrayList accountsLogOnAsService;
ArrayList accountsLogOnAsCreateGlobalObjects;
ArrayList accountsDenyLogonAsBatch;
ArrayList accountsDenyLogonAsService;
try
{
accountsDenyLogonAsBatch = GetUsersWithPrivilege("SeDenyBatchLogonRight");//SeDenyBatchLogonRight
if (accountsDenyLogonAsBatch.Contains(Username)) return 1;
accountsDenyLogonAsService = GetUsersWithPrivilege("SeDenyServiceLogonRight");//SeDenyServiceLogonRight
if (accountsDenyLogonAsService.Contains(Username)) return 1;
accountsLogOnAsBatch = GetUsersWithPrivilege("SeBatchLogonRight");//SeServiceLogonRight //SeCreateGlobalPrivilege
if (accountsLogOnAsBatch.Contains(Username))
{
accountsLogOnAsService = GetUsersWithPrivilege("SeServiceLogonRight");//SeServiceLogonRight //SeCreateGlobalPrivilege
if (accountsLogOnAsService.Contains(Username))
{
accountsLogOnAsCreateGlobalObjects = GetUsersWithPrivilege("SeCreateGlobalPrivilege");//SeServiceLogonRight //SeCreateGlobalPrivilege
if (accountsLogOnAsCreateGlobalObjects.Contains(Username))
{
return 0;
}
else
{
return 1;
}
}
else
{
return 1;
}
}
else
{
return 1;
}
}
catch (Exception)
{
return 1;
}
}

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 ArrayList GetUsersWithPrivilege(string privilege)
{
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
privileges[0] = InitLsaString(privilege);

IntPtr buffer;
int count;
uint ret =
Win32Sec.LsaEnumerateAccountsWithUserRight(lsaHandle, privileges, out buffer, out count);

if (ret != 0 && privilege != "SeDenyBatchLogonRight" && privilege != "SeDenyServiceLogonRight")
{
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));
}

LSA_ENUMERATION_INFORMATION[] lsaInfo = new LSA_ENUMERATION_INFORMATION[count];
for (int i = 0, elemOffs = (int)buffer; i < count; i++)
{
lsaInfo[i] = (LSA_ENUMERATION_INFORMATION)Marshal.PtrToStructure((IntPtr)elemOffs, typeof(LSA_ENUMERATION_INFORMATION));
elemOffs += Marshal.SizeOf(typeof(LSA_ENUMERATION_INFORMATION));
}

LSA_HANDLE domains;
LSA_HANDLE names;
int LSA_LOOKUP_RETURN_LOCAL_NAMES = 0;

ret = Win32Sec.LsaLookupSids(lsaHandle, lsaInfo.Length, buffer, out domains, out names);
//ret = Win32Sec.LsaLookupSids2(lsaHandle, LSA_LOOKUP_RETURN_LOCAL_NAMES, lsaInfo.Length, buffer, out domains, out names);

if (ret != 0)
{
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));
}

string[] retNames = new string[count];
List currentDomain = new List();
int domainCount = 0;

LSA_TRANSLATED_NAME[] lsaNames = new LSA_TRANSLATED_NAME[count];
for (int i = 0, elemOffs = (int)names; i < count; i++)
{
lsaNames[i] = (LSA_TRANSLATED_NAME)Marshal.PtrToStructure((LSA_HANDLE)elemOffs, typeof(LSA_TRANSLATED_NAME));
elemOffs += Marshal.SizeOf(typeof(LSA_TRANSLATED_NAME));

LSA_UNICODE_STRING name = lsaNames[i].Name;
retNames[i] = name.Buffer.Substring(0, name.Length / 2);

if (!currentDomain.Contains(lsaNames[i].DomainIndex))
{
domainCount = domainCount + 1;
currentDomain.Add(lsaNames[i].DomainIndex);
}

}

string[] domainPtrNames = new string[count];

LSA_REFERENCED_DOMAIN_LIST[] lsaDomainNames = new LSA_REFERENCED_DOMAIN_LIST[count];

for (int i = 0, elemOffs = (int)domains; i < count; i++)
{
lsaDomainNames[i] = (LSA_REFERENCED_DOMAIN_LIST)Marshal.PtrToStructure((LSA_HANDLE)elemOffs, typeof(LSA_REFERENCED_DOMAIN_LIST));
elemOffs += Marshal.SizeOf(typeof(LSA_REFERENCED_DOMAIN_LIST));
}

LSA_TRUST_INFORMATION[] lsaDomainName = new LSA_TRUST_INFORMATION[count];
string[] domainNames = new string[domainCount];

for (int i = 0, elemOffs = (int)lsaDomainNames[i].Domains; i < domainCount; i++)
{
lsaDomainName[i] = (LSA_TRUST_INFORMATION)Marshal.PtrToStructure((LSA_HANDLE)elemOffs, typeof(LSA_TRUST_INFORMATION));
elemOffs += Marshal.SizeOf(typeof(LSA_TRUST_INFORMATION));

LSA_UNICODE_STRING tempDomain = lsaDomainName[i].Name;
//if(tempDomain.Buffer != null)
//{
domainNames[i] = tempDomain.Buffer.Substring(0, tempDomain.Length / 2);
//}
}

//string[] domainUserName = new string[count];
ArrayList domainUserName = new ArrayList();

for (int i = 0; i < lsaNames.Length; i++)
{
//domainUserName[i] = domainNames[lsaNames[i].DomainIndex] + "\\" + retNames[i];
domainUserName.Add(domainNames[lsaNames[i].DomainIndex] + "\\" + retNames[i]);
}


Win32Sec.LsaFreeMemory(buffer);
Win32Sec.LsaFreeMemory(domains);
Win32Sec.LsaFreeMemory(names);

//return retNames;
//return domainNames;
return domainUserName;
}

public void AddPrivileges(string account, string privilege)
{
IntPtr pSid = GetSIDInformation(account);
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
privileges[0] = InitLsaString(privilege);
uint ret = Win32Sec.LsaAddAccountRights(lsaHandle, pSid, privileges, 1);

if (ret == 0)
{
if (this._writeToConsole)
{
Console.WriteLine("Added: {0} to {1} successfully.", account, privilege);
}
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 RemovePrivileges(string account, string privilege)
{
IntPtr pSid = GetSIDInformation(account);
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
privileges[0] = InitLsaString(privilege);
uint ret = Win32Sec.LsaRemoveAccountRights(lsaHandle, pSid, false, privileges, 1);

if (ret == 0)
{
if (this._writeToConsole)
{
Console.WriteLine("Removed: {0} from {1} successfully.", account, privilege);
}
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

IntPtr GetSIDInformation(string account)
{
LSA_UNICODE_STRING[] names = new LSA_UNICODE_STRING[1];
LSA_TRANSLATED_SID2 lts;
IntPtr tsids = IntPtr.Zero;
IntPtr tdom = IntPtr.Zero;
names[0] = InitLsaString(account);
lts.Sid = IntPtr.Zero;
int ret = Win32Sec.LsaLookupNames2(lsaHandle, 0, 1, names, ref tdom, ref tsids);
if (ret != 0)
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError(ret));
lts = (LSA_TRANSLATED_SID2)Marshal.PtrToStructure(tsids,
typeof(LSA_TRANSLATED_SID2));
Win32Sec.LsaFreeMemory(tsids);
Win32Sec.LsaFreeMemory(tdom);
return lts.Sid;
}

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));

// If unicode issues then do this instead of previous two line
//lus.Length = (ushort)(s.Length * 2); // Unicode char is 2 bytes
//lus.MaximumLength = (ushort)(lus.Length + 2)

return lus;
}

public bool WriteToConsole
{
set { this._writeToConsole = value; }
}
}
}