2009-07-18 6 views
6

Aquí hay un código fuente de C# que implementa una DLL no administrada (advapi32).¿Por qué LsaAddAccountRights devolvería 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); 
} 

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 capturado, el mensaje dentro de la Win32Exception es: "el parámetro es incorrecto"

El código se ejecuta en Windows Web Servidor 2008. Puedo verificar que la cuenta existe, y este código funciona bien en otro servidor ... No estoy seguro de si esto podría haber sido causado por Windows 2008 SP2. Estoy pensando que me he olvidado de instalar algo, pero no puedo pensar en lo que ...

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

Respuesta

0

Me encontré con el mismo error al llamar a 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 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); 
1

pude conseguir esta trabajando en una caja, pero luego en otra caja en la que error con el error que recibió:

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

Descubrí que la causa de este problema para mí tenía que ver con la arquitectura del proceso que ejecutaba el código. Estaba ejecutando un proceso de msbuild de 32 bits que funcionó bien, pero cuando usé el msbuild.exe de 64 bits para ejecutarlo, falló con este error.

Espero que ayude!

Saludos, Brandon

0

yo encontramos este problema está relacionado con .NET 4.0. Baja tu proyecto a .NET 3.5 y funcionará.

+0

La degradación no es una opción real. Avanzar con una solución es mejor que retroceder. – Snowy

6

Siguiendo el enlace que aparece a través de un código en 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 (una estructura LSA_TRANSLATED_SID2) contiene un puntero que apunta a la memoria que se libera por la llamada a Win32Sec.LsaFreeMemory. Usar el puntero después de liberar la memoria es una mala práctica y tendrá resultados impredecibles, incluso podría "funcionar".

Al ajustar el código en el enlace utilizando la clase SecurityIdentifier (.Net 2 y superior) a lo largo de una pequeña limpieza de código innecesario, se 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; 
     } 
    } 
} 
1

lts.Sid ​​se libera antes de volver en GetSIDInformation. Moviendo 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)); 
    } 
Cuestiones relacionadas