¿Por qué LsaAddAccountRights podría devolver STATUS_INVALID_PARAMETER?

StackOverflow https://stackoverflow.com/questions/1147914

  •  18-09-2019
  •  | 
  •  

Pregunta

A continuación se muestra un código fuente de C# que implementa una DLL no administrada (advapi32).

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

Los valores de las variables en tiempo de ejecución son los siguientes:

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

Cuando se detecta, el mensaje dentro de Win32Exception es:"El parámetro es incorrecto"

El código se ejecuta en Windows Web Server 2008.Puedo verificar que la cuenta existe y que este código funciona bien en otro servidor...No estoy seguro de si esto pudo haber sido causado por Windows 2008 SP2.Estoy pensando que me olvidé de instalar algo, pero no se me ocurre qué...

El código es de: http://weblogs.asp.net/avnerk/archive/2007/05/10/granting-user-rights-in-c.aspx

¿Fue útil?

Solución 2

No pude conseguir que esto funcione, por lo que en lugar de eso utiliza el código fuente del proyecto CodeProject, Funciones de LSA -. Los privilegios y la suplantación que funciona muy bien

Otros consejos

Siguiendo el enlace proporcionado a través de al código en http: //www.hightechtalks .com / csharp / LSA-funciones-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 (una estructura LSA_TRANSLATED_SID2) contiene un puntero que apunta a la memoria que se libera por la llamada a Win32Sec.LsaFreeMemory . Usando el puntero después se libera la memoria es una mala práctica y tendrá resultados impredecibles -. Puede ser que incluso el "trabajo"

Optimizando el código en el enlace utilizando la clase SecurityIdentifier (.Net 2 y superior) a lo largo de un poco de limpieza de código que no sean necesarios evita el problema de memoria.

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

lts.Sid ​​se libera antes de regresar en GetSIDInformation.Sacando los códigos de GetSIDInformation.Funcionó bien para .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));
    }

Me encontré con el mismo error al llamar LsaAddAccountRights y descubrí que estaba usando sizeof (char) en lugar de sizeof (wchar) al inicializar LSA_UNICODE_STRING.

he comprobado el código en http://www.codeproject.com/KB/cs /lsadotnet.aspx y se encontró problema similar:

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

Debe ser algo como:

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

Yo era capaz de conseguir este trabajo en una caja, pero luego en otro cuadro que falló con el error recibido:

System.ComponentModel.Win32Exception: El parámetro es incorrecto

Me descubierto que la causa principal de este problema para mí tenía que ver con la arquitectura del proceso que se estaba ejecutando el código. Yo estaba corriendo un proceso de 32 bits msbuild que funcionaba bien, pero cuando he utilizado la msbuild.exe 64 bits para ejecutar este Fracasó con este error.

Espero que ayude!

Saludos, Brandon

He encontrado este problema está relacionado con .NET 4.0. Rebajar su proyecto para .NET 3.5 y funcionará.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top