Home All Groups Group Topic Archive Search About

LsaOpenPolicy : Attempted to read or write protected memory

Author
6 Nov 2006 11:08 AM
Adrian Wallis
Hello,

I'm trying to call LsaOpenPolicy, but get the error
'System.AccessViolationException'.

I originally tried a conversion from working VB6 code and I've compared
the code with working C# code and cannot see where the problem lies -
can anyone help to point out the problem please:

    Structure LSA_UNICODE_STRING
        Dim Length As Short
        Dim MaximumLength As Short
        Dim Buffer As String
    End Structure
    Structure LSA_OBJECT_ATTRIBUTES
        Dim Length As Integer
        Dim RootDirectory As IntPtr
        Dim ObjectName As IntPtr
        Dim Attributes As Integer
        Dim SecurityDescriptor As IntPtr
        Dim SecurityQualityOfService As IntPtr
    End Structure
    Declare Unicode Function LsaOpenPolicy Lib "advapi32.dll" (ByRef
SystemName() As LSA_UNICODE_STRING, ByRef ObjectAttributes As
LSA_OBJECT_ATTRIBUTES, ByVal DesiredAccess As Int32, ByRef PolicyHandle
As IntPtr) As Int32
    Private POLICY_ALL_ACCESS As Integer = &HF0FFF

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Me.Load
        Dim SystemName(0) As LSA_UNICODE_STRING
        SystemName(0) = New LSA_UNICODE_STRING
        'initialize a pointer for the policy handle
        Dim PolicyHandle As IntPtr = IntPtr.Zero
        'these attributes are not used, but LsaOpenPolicy wants them to
exists
        Dim ObjectAttributes As New LSA_OBJECT_ATTRIBUTES
        ObjectAttributes.RootDirectory = IntPtr.Zero
        ObjectAttributes.ObjectName = IntPtr.Zero
        ObjectAttributes.Attributes = 0
        ObjectAttributes.SecurityDescriptor = IntPtr.Zero
        ObjectAttributes.SecurityQualityOfService = IntPtr.Zero
        ObjectAttributes.Length = 24 ' IN C# :
Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));
        'get a policy handle
        SystemName(0).Length = "192.168.1.1".Length * 2 ' Can't get
UnicodeEncoding.CharSize to work? How to declare?
        SystemName(0).MaximumLength = ("192.168.1.1".Length + 1) * 2 '
Can't get UnicodeEncoding.CharSize to work? How to declare?
        SystemName(0).Buffer = "192.168.1.1"
        Dim ResultPolicy As UInteger
        Dim Access = POLICY_ALL_ACCESS
        ResultPolicy = LsaOpenPolicy(SystemName, ObjectAttributes,
Access, PolicyHandle)

Many thanks
Adrian

Author
6 Nov 2006 5:58 PM
Mattias Sjögren
Adrian,

>    Declare Unicode Function LsaOpenPolicy Lib "advapi32.dll" (ByRef
>SystemName() As LSA_UNICODE_STRING, ByRef ObjectAttributes As
>LSA_OBJECT_ATTRIBUTES, ByVal DesiredAccess As Int32, ByRef PolicyHandle
>As IntPtr) As Int32

The first parameter shouldn't be an array, just a single
LSA_UNICODE_STRING.


>        'these attributes are not used, but LsaOpenPolicy wants them to
>exists
>        Dim ObjectAttributes As New LSA_OBJECT_ATTRIBUTES
>        ObjectAttributes.RootDirectory = IntPtr.Zero
>        ObjectAttributes.ObjectName = IntPtr.Zero
>        ObjectAttributes.Attributes = 0
>        ObjectAttributes.SecurityDescriptor = IntPtr.Zero
>        ObjectAttributes.SecurityQualityOfService = IntPtr.Zero
>        ObjectAttributes.Length = 24 ' IN C# :
>Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));

FYI, all members are initialized to zero by default so doing it
explicitly isn't really needed.

And you can use Marshal.SizeOf from VB as well.


Mattias

--
Mattias Sjögren [C# MVP]  mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Author
7 Nov 2006 11:09 AM
Adrian Wallis
Thanks for that, the problem appears to be with the LSA_UNICODE_STRING
part.

If I set pass it as NOTHING it works fine and gets a handle to local
machine, the problem comes when I try to use it on a remote computer.

Having stepped through the C# version and the VB.NET version I cannot
see any differences in what is being passed, or how it's being passed.

I'm totallay stumped as to what's causing the error.


Mattias Sjögren wrote:
Show quoteHide quote
> Adrian,
>
> >    Declare Unicode Function LsaOpenPolicy Lib "advapi32.dll" (ByRef
> >SystemName() As LSA_UNICODE_STRING, ByRef ObjectAttributes As
> >LSA_OBJECT_ATTRIBUTES, ByVal DesiredAccess As Int32, ByRef PolicyHandle
> >As IntPtr) As Int32
>
> The first parameter shouldn't be an array, just a single
> LSA_UNICODE_STRING.
>
>
> >        'these attributes are not used, but LsaOpenPolicy wants them to
> >exists
> >        Dim ObjectAttributes As New LSA_OBJECT_ATTRIBUTES
> >        ObjectAttributes.RootDirectory = IntPtr.Zero
> >        ObjectAttributes.ObjectName = IntPtr.Zero
> >        ObjectAttributes.Attributes = 0
> >        ObjectAttributes.SecurityDescriptor = IntPtr.Zero
> >        ObjectAttributes.SecurityQualityOfService = IntPtr.Zero
> >        ObjectAttributes.Length = 24 ' IN C# :
> >Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));
>
> FYI, all members are initialized to zero by default so doing it
> explicitly isn't really needed.
>
> And you can use Marshal.SizeOf from VB as well.
>
>
> Mattias
>
> --
> Mattias Sjögren [C# MVP]  mattias @ mvps.org
> http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
> Please reply only to the newsgroup.
Author
7 Nov 2006 11:19 AM
Adrian Wallis
I've managed to fix the first error with the following code:

        Dim SystemName As LSA_UNICODE_STRING
        SystemName = New LSA_UNICODE_STRING
        UserAccount = "tenyas\zwan"
        Dim ObjectAttributes As New LSA_OBJECT_ATTRIBUTES
        'get a policy handle
        SystemName = InitLSAString("")
        Dim ResultPolicy As Integer
        Dim Access = POLICY_ALL_ACCESS
        ResultPolicy = LsaOpenPolicy(SystemName, ObjectAttributes,
Access, PolicyHandle)
        If ResultPolicy <> 0 Then
            Debug.Print(LsaNtStatusToWinError(ResultPolicy))
        End If

which works fine. As soon as I add a remote machine name though, it
fails with error 1722 (RPC Server unavailable), I know this isn't the
case as it happens against any machine. I can only assume that the name
isn't being passed correctly as unicode?

Please help someone - it's driving me crazy.

Thanks
Adrian

Adrian Wallis wrote:
Show quoteHide quote
> Thanks for that, the problem appears to be with the LSA_UNICODE_STRING
> part.
>
> If I set pass it as NOTHING it works fine and gets a handle to local
> machine, the problem comes when I try to use it on a remote computer.
>
> Having stepped through the C# version and the VB.NET version I cannot
> see any differences in what is being passed, or how it's being passed.
>
> I'm totallay stumped as to what's causing the error.
>
>
> Mattias Sjögren wrote:
> > Adrian,
> >
> > >    Declare Unicode Function LsaOpenPolicy Lib "advapi32.dll" (ByRef
> > >SystemName() As LSA_UNICODE_STRING, ByRef ObjectAttributes As
> > >LSA_OBJECT_ATTRIBUTES, ByVal DesiredAccess As Int32, ByRef PolicyHandle
> > >As IntPtr) As Int32
> >
> > The first parameter shouldn't be an array, just a single
> > LSA_UNICODE_STRING.
> >
> >
> > >        'these attributes are not used, but LsaOpenPolicy wants them to
> > >exists
> > >        Dim ObjectAttributes As New LSA_OBJECT_ATTRIBUTES
> > >        ObjectAttributes.RootDirectory = IntPtr.Zero
> > >        ObjectAttributes.ObjectName = IntPtr.Zero
> > >        ObjectAttributes.Attributes = 0
> > >        ObjectAttributes.SecurityDescriptor = IntPtr.Zero
> > >        ObjectAttributes.SecurityQualityOfService = IntPtr.Zero
> > >        ObjectAttributes.Length = 24 ' IN C# :
> > >Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));
> >
> > FYI, all members are initialized to zero by default so doing it
> > explicitly isn't really needed.
> >
> > And you can use Marshal.SizeOf from VB as well.
> >
> >
> > Mattias
> >
> > --
> > Mattias Sjögren [C# MVP]  mattias @ mvps.org
> > http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
> > Please reply only to the newsgroup.
Author
7 Nov 2006 11:52 AM
Adrian Wallis
I've managed to fix the problem by changing the structure slightly:

    Structure LSA_UNICODE_STRING
        Dim Length As Short
        Dim MaximumLength As Short

<System.Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPWStr)>
Dim buffer As String
    End Structure

The full code if anyone wants is :

    Structure LSA_UNICODE_STRING
        Dim Length As Short
        Dim MaximumLength As Short

<System.Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.LPWStr)>
Dim buffer As String
    End Structure
    Public Enum SID_NAME_USE
        SidTypeUser = 1
        SidTypeGroup = 2
        SidTypeDomain = 3
        SidTypeAlias = 4
        SidTypeWellKnownGroup = 5
        SidTypeDeletedAccount = 6
        SidTypeInvalid = 7
        SidTypeUnknown = 8
    End Enum
    Structure LSA_OBJECT_ATTRIBUTES
        Dim Length As Integer
        Dim RootDirectory As IntPtr
        Dim ObjectName As IntPtr
        Dim Attributes As Integer
        Dim SecurityDescriptor As IntPtr
        Dim SecurityQualityOfService As IntPtr
    End Structure
    Structure LSA_translated_sid
        Dim use As SID_NAME_USE
        Dim RelativeID As ULong
        Dim DomainIndex As Long
    End Structure
    Public UserAccount As String
    Dim PolicyHandle As IntPtr = IntPtr.Zero
    Private Declare Function LsaNtStatusToWinError Lib "advapi32.dll"
(ByVal NTStatus As Int32) As Int32
    Declare Unicode Function LsaOpenPolicy Lib "advapi32.dll" (ByRef
SystemName As LSA_UNICODE_STRING, ByRef ObjectAttributes As
LSA_OBJECT_ATTRIBUTES, ByVal DesiredAccess As Int32, ByRef PolicyHandle
As IntPtr) As Int32
    Private POLICY_ALL_ACCESS As Integer = &HF0FFF
    Private Declare Auto Function LookupAccountName Lib "advapi32.dll"
(ByVal lpSystemName As String, ByVal lpAccountName As String, ByVal Sid
As IntPtr, ByRef cbSid As Integer, ByVal lpReferenceDomainName As
String, ByRef cchReferencedDomainName As Integer, ByRef peUse As
Integer) As Boolean
    Private Declare Unicode Function LsaAddAccountRights Lib
"advapi32.dll" (ByVal PolicyHandle As IntPtr, ByVal AccountSid As
IntPtr, ByRef UserRights As LSA_UNICODE_STRING, ByVal CountOfRights As
Int32) As Int32
    Private Sub Form1_Load(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Me.Load
        Dim SystemName As LSA_UNICODE_STRING
        SystemName = New LSA_UNICODE_STRING
        UserAccount = "domain\user"
        Dim ObjectAttributes As New LSA_OBJECT_ATTRIBUTES
        'get a policy handle
        SystemName = InitLSAString("192.168.1.1")
        Dim ResultPolicy As Integer
        Dim Access = POLICY_ALL_ACCESS
        ResultPolicy = LsaOpenPolicy(SystemName, ObjectAttributes,
Access, PolicyHandle)
        If ResultPolicy <> 0 Then
            Debug.Print(LsaNtStatusToWinError(ResultPolicy))
        End If
        Dim tSID As IntPtr
        Dim lngUse As Int32 = 0
        tSID = fncLookupAccountName("192.168.1.1", "domain\user", tSID,
Nothing, lngUse)
        Dim Privileges As LSA_UNICODE_STRING = New LSA_UNICODE_STRING
        Privileges = InitLSAString("SeServiceLogonRight")
        Dim test As Integer
        test = LsaAddAccountRights(PolicyHandle, tSID, Privileges, 1)
        Debug.Print(LsaNtStatusToWinError(test))
    End Sub
    Public Function fncLookupAccountName(ByVal strSystemName As String,
ByVal strName As String, ByVal tSID As IntPtr, ByRef
strReferencedDomainName As String, ByRef lngUse As Long) As Long
        Dim ret As Boolean
        Dim ptrSid As IntPtr
        Dim cbSid As Integer
        Dim refDomainName As New System.Text.StringBuilder
        Dim cbRefDomainName As Integer
        Dim peUse As SID_NAME_USE
        'First get the buffer sizes
        ret = LookupAccountName(strSystemName, strName, Nothing, cbSid,
Nothing, cbRefDomainName, peUse)
        'Adjust the buffers to the needed size
        ptrSid =
System.Runtime.InteropServices.Marshal.AllocHGlobal(cbSid)
        refDomainName.EnsureCapacity(cbRefDomainName)
        'Get the data again, now with the changed buffers
        ret = LookupAccountName(strSystemName, strName, ptrSid, cbSid,
refDomainName.ToString, cbRefDomainName, peUse)
        If ret Then
            Return ptrSid
        End If
    End Function
    Public Function InitLSAString(ByVal Input As String) As
LSA_UNICODE_STRING
        Dim LSAString As New LSA_UNICODE_STRING
        LSAString.Length = Input.Length *
System.Text.UnicodeEncoding.CharSize
        LSAString.MaximumLength = (Input.Length + 1) *
System.Text.UnicodeEncoding.CharSize
        LSAString.buffer = Input
        Return LSAString
    End Function

I hope this helps someone.
Adrian