2009-07-18 46 views
6

下面是一些實現非託管DLL(advapi32)的C#源代碼。是爲什麼LsaAddAccountRights會返回STATUS_INVALID_PARAMETER?

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

    int error = Win32Sec.LsaNtStatusToWinError((int)ret); 
    throw new Win32Exception(error); 
} 

在運行時的變量值如下:

privilege: "SeServiceLogonRight" 
account: "named" 
ret: 3221225485 (STATUS_INVALID_PARAMETER) 
error: 87 

抓時,將Win32Exception內的消息是:「參數不正確」

的代碼在Windows網絡上運行Server 2008.我可以驗證該帳戶是否存在,並且此代碼可以在另一臺服務器上正常工作......我不確定這是否可能是由Windows 2008 SP2引起的。我在想,我忘了安裝的東西,但我想不出什麼...

代碼爲:http://weblogs.asp.net/avnerk/archive/2007/05/10/granting-user-rights-in-c.aspx

回答

0

我在調用LsaAddAccountRights時遇到了同樣的錯誤,並且在初始化LSA_UNICODE_STRING時發現我使用sizeof(char)而不是sizeof(wchar)。

我檢查的代碼在http://www.codeproject.com/KB/cs/lsadotnet.aspx,發現類似的問題:

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

應該是這樣的:

lus.Length = (ushort)(s.Length * UnicodeEncoding.CharSize); 
lus.MaximumLength = (ushort)(lus.Length + UnicodeEncoding.CharSize); 
1

我能得到一個盒子這個工作,但隨後在另一臺電腦它由於收到的錯誤而失敗:

System.ComponentModel.Win32Exception:參數不正確

我發現這個問題的根源與我運行代碼的進程的體系結構有關。我正在運行一個msbuild 32位進程,它工作正常,但是當我使用64位msbuild.exe來運行它時,它失敗並出現此錯誤。

我希望有幫助!

問候, 布蘭登

0

我發現這個問題涉及到.NET 4.0。將您的項目降級到.NET 3.5,它會起作用。

+0

降級不是一個真正的選擇。前進與修復比倒退更好。 – Snowy 2012-10-03 17:06:23

6

以下通過對代碼在http://www.hightechtalks.com/csharp/lsa-functions-276626.html

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

LTS(一個LSA_TRANSLATED_SID2結構)提供的鏈接包含指向在由該呼叫釋放到Win32Sec.LsaFreeMemory存儲器的指針。內存釋放後使用指針是不好的做法,並會產生不可預測的結果 - 它甚至可能「工作」。

通過使用SecurityIdentifier類(.Net 2及更高版本)對鏈接中的代碼進行調整,可以避免內存問題。

using System; 

namespace Willys.LsaSecurity 
{ 
    using System.ComponentModel; 
    using System.Runtime.InteropServices; 
    using System.Security; 
    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), 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")] 
     internal static extern int LsaNtStatusToWinError(int NTSTATUS); 

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

    } 

    sealed class Sid : IDisposable 
    { 
     public IntPtr pSid = IntPtr.Zero; 
     public SecurityIdentifier sid = null; 

     public Sid(string account) 
     { 
     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; 

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

lts.Sid​​在GetSIDInformation返回之前被釋放。 將GetSIDInformation的代碼移出。它適用於.Net 4.5。

public void AddPrivileges(string account, string privilege) 
    { 
     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 ret1 = Win32Sec.LsaLookupNames2(lsaHandle, 0, 1, names, ref tdom, ref tsids); 
     if (ret1 != 0) 
      throw new Win32Exception(Win32Sec.LsaNtStatusToWinError(ret1)); 
     lts = (LSA_TRANSLATED_SID2)Marshal.PtrToStructure(tsids, typeof(LSA_TRANSLATED_SID2)); 
     IntPtr pSid = lts.Sid;    
     //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); 
     Win32Sec.LsaFreeMemory(tsids); 
     Win32Sec.LsaFreeMemory(tdom); 
     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)); 
    }