8

アンマネージDLL(advapi32)を実装するC#ソースコードを次に示します。

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内のメッセージは次のようになります。「パラメータが正しくありません」

コードはWindowsWebServer 2008で実行されています。アカウントが存在することを確認でき、このコードは別のサーバーで正常に機能します...これがWindows2008SP2が原因である可能性があるかどうかはわかりません。何かをインストールするのを忘れたと思っているのですが、なにかわからない…

コードは次のとおりです:http ://weblogs.asp.net/avnerk/archive/2007/05/10/granting-user-rights-in-c.aspx

4

6 に答える 6

10

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;
      }
   }
}
于 2013-01-22T22:29:03.177 に答える
2

これを機能させることができなかったので、代わりに CodeProject プロジェクトのソース コード、LSA Functions - Privileges and Impersonationを使用しました。

于 2009-07-18T19:16:24.027 に答える
2

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));
    }
于 2013-04-26T03:04:56.583 に答える
1

あるボックスではこれを機能させることができましたが、別のボックスでは、受け取ったエラーで失敗しました:

System.ComponentModel.Win32Exception: パラメータが正しくありません

この問題の根本的な原因は、コードを実行していたプロセスのアーキテクチャに関係していることがわかりました。正常に動作する msbuild 32 ビット プロセスを実行していましたが、64 ビット msbuild.exe を使用してこれを実行すると、このエラーで失敗しました。

それが役立つことを願っています!

よろしく、 ブランドン

于 2011-09-27T20:00:59.657 に答える
1

LsaAddAccountRights を呼び出したときに同じエラーが発生し、LSA_UNICODE_STRING を初期化するときに sizeof(wchar) ではなく sizeof(char) を使用していたことがわかりました。

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);
于 2011-04-08T07:30:44.430 に答える
0

この問題は .NET 4.0 に関連していることがわかりました。プロジェクトを .NET 3.5 にダウングレードすると、機能します。

于 2012-04-19T22:46:01.587 に答える