HighTechTalks DotNet Forums  

LSA functions

CSharp microsoft.public.dotnet.languages.csharp


Discuss LSA functions in the CSharp forum.

Reply
 
Thread Tools Search this Thread Display Modes
  #1  
Old   
Morten
 
Posts: n/a

Default LSA functions - 03-09-2005 , 08:17 AM






Hi!

Has anyone been able to use LSA functions to grant or remove privileges
to/from users? I'm trying to find a way to programmatically set the "Deny
logon through Terminal Services" privilege for certain users. If someone has
a small example of how to use these functions from C# it would be very
helpful.

Thanks in advance

Morten





Reply With Quote
  #2  
Old   
Willy Denoyette [MVP]
 
Posts: n/a

Default Re: LSA functions - 03-09-2005 , 12:11 PM







"Morten" <morten_skovgaard (AT) hotmail (DOT) com> wrote

Quote:
Hi!

Has anyone been able to use LSA functions to grant or remove privileges
to/from users? I'm trying to find a way to programmatically set the "Deny
logon through Terminal Services" privilege for certain users. If someone
has a small example of how to use these functions from C# it would be very
helpful.

Thanks in advance

Morten

Here a simple class that should do the job (use at own risk). Note that IMO,
this kind of PInvoke stuff could better be done using MC++ (C++/CLI) or
using System.Management (WMI) and RSOP.


namespace Willys.LsaSecurity
{
using System.Runtime.InteropServices;
using System.Security;
using System.Management;
using System.Runtime.CompilerServices;
using System.ComponentModel;

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),
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 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
{
[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;
}

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 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 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)
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;
Console.WriteLine("String account: {0}", names[0].Length);
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));
return lus;
}
}
}


// usage....

using (Willys.LsaSecurity.LsaWrapper lsa = new
Willys.LsaSecurity.LsaWrapper())
{
// add SeDenyRemoteInteractiveLogonRight will effectively deny TS access to
someAccount
lsa.AddPrivileges("someAccount",
"SeDenyRemoteInteractiveLogonRight");
}


Willy.




Reply With Quote
  #3  
Old   
Morten
 
Posts: n/a

Default Re: LSA functions - 03-10-2005 , 03:28 AM



Hi Willy!

Thanks for your suggestion. I'm having a few problems using your code. I get
this error:

LSA.cs(218): sizeof can only be used in an unsafe context (consider using
System.Runtime.InteropServices.Marshal.SizeOf)

Any idea how that can be solved? Also, I've been looking for a way to use
WMI - preferably using a vb script - to do the same so if you have any idea
how this can be done I'd be greatful.

Best regards

Morten

"Willy Denoyette [MVP]" <willy.denoyette (AT) pandora (DOT) be> wrote

Quote:
"Morten" <morten_skovgaard (AT) hotmail (DOT) com> wrote in message
news:elgnELLJFHA.572 (AT) tk2msftngp13 (DOT) phx.gbl...
Hi!

Has anyone been able to use LSA functions to grant or remove privileges
to/from users? I'm trying to find a way to programmatically set the "Deny
logon through Terminal Services" privilege for certain users. If someone
has a small example of how to use these functions from C# it would be
very helpful.

Thanks in advance

Morten


Here a simple class that should do the job (use at own risk). Note that
IMO, this kind of PInvoke stuff could better be done using MC++ (C++/CLI)
or using System.Management (WMI) and RSOP.


namespace Willys.LsaSecurity
{
using System.Runtime.InteropServices;
using System.Security;
using System.Management;
using System.Runtime.CompilerServices;
using System.ComponentModel;

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),
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 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
{
[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;
}

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 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 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)
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;
Console.WriteLine("String account: {0}", names[0].Length);
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));
return lus;
}
}
}


// usage....

using (Willys.LsaSecurity.LsaWrapper lsa = new
Willys.LsaSecurity.LsaWrapper())
{
// add SeDenyRemoteInteractiveLogonRight will effectively deny TS access
to someAccount
lsa.AddPrivileges("someAccount",
"SeDenyRemoteInteractiveLogonRight");
}


Willy.





Reply With Quote
  #4  
Old   
Willy Denoyette [MVP]
 
Posts: n/a

Default Re: LSA functions - 03-10-2005 , 05:09 AM




"Morten" <morten_skovgaard (AT) hotmail (DOT) com> wrote

Quote:
Hi Willy!

Thanks for your suggestion. I'm having a few problems using your code. I
get this error:

LSA.cs(218): sizeof can only be used in an unsafe context (consider using
System.Runtime.InteropServices.Marshal.SizeOf)

Any idea how that can be solved? Also, I've been looking for a way to use
WMI - preferably using a vb script - to do the same so if you have any
idea how this can be done I'd be greatful.

Best regards

Morten

Never understood why sizeof(char) needs an unsafe context, but you can get
arround it by this...

lus.Length = (ushort)(s.Length * 2); // Unicode char is 2 bytes
lus.MaximumLength = (ushort)(lus.Length + 2)

Assuming you are running in a AD, you should definitely take a look at Group
policy management (GPO) to apply these kind of privileges, that way you
don't have to write any code.

Willy.






Reply With Quote
Reply




Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off



Powered by vBulletin Version 3.5.4
Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.