2009-07-18 102 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)); 
    }