2009-01-18 8 views
6

Puedo encontrar todo tipo de cosas sobre cómo programar para DCOM, pero prácticamente nada sobre cómo establecer/verificar la seguridad mediante programación.dcomcnfg funcionalidad programáticamente

No estoy intentando recrear dcomcnfg, pero si supiera cómo reproducir toda la funcionalidad de dcomcnfg en C# (preferido, o VB.net), entonces mi objetivo está a la vista.

Parece que no puedo encontrar ningún buen recurso en esto, no hay API de código abierto o incluso ejemplos rápidos de cómo hacer cada paso. Incluso aquí DCOM o dcomcnfg arroja pocos resultados y ninguno realmente acerca de cómo establecer/verificar/enumerar la seguridad.

Si alguien tiene algunos consejos para una API abierta o algunos ejemplos, lo agradecería.

Respuesta

10

La respuesta publicada por Daniel fue HUGELY útil. ¡Muchas gracias, Daniel!

Un problema con Microsoft's documentation es que indican que los valores de registro contienen una ACL en formato binario. Entonces, por ejemplo, si estuviera tratando de establecer el acceso predeterminado de la máquina (en lugar de por proceso), estaría accediendo a la clave de registro HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Ole \ DefaultAccessPermission. Sin embargo, en mis intentos iniciales de acceder a esta clave utilizando la clase System.Security.AccessControl.RawACL fallaron.

Como indica el código de Daniel, el valor no es realmente una ACL, pero en realidad es un SecurityDescriptor con la ACL.

Por lo tanto, aunque sé que esta publicación es antigua, voy a publicar mi solución para verificar y establecer la configuración de seguridad y agregar NetworkService para acceso local predeterminado. Por supuesto, podrías tomar esto y hacerlo mejor, estoy seguro, pero para empezar solo necesitarías cambiar la llave y la máscara de acceso.

static class ComACLRights{ 
    public const int COM_RIGHTS_EXECUTE= 1; 
    public const int COM_RIGHTS_EXECUTE_LOCAL = 2; 
    public const int COM_RIGHTS_EXECUTE_REMOTE = 4; 
    public const int COM_RIGHTS_ACTIVATE_LOCAL = 8; 
    public const int COM_RIGHTS_ACTIVATE_REMOTE = 16; 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     var value = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Ole", "DefaultAccessPermission", null); 

     RawSecurityDescriptor sd; 
     RawAcl acl; 

     if (value == null) 
     { 
      System.Console.WriteLine("Default Access Permission key has not been created yet"); 
      sd = new RawSecurityDescriptor(""); 
     }else{ 
      sd = new RawSecurityDescriptor(value as byte[], 0); 
     } 
     acl = sd.DiscretionaryAcl; 
     bool found = false; 
     foreach (CommonAce ca in acl) 
     { 
      if (ca.SecurityIdentifier.IsWellKnown(WellKnownSidType.NetworkServiceSid)) 
      { 
       //ensure local access is set 
       ca.AccessMask |= ComACLRights.COM_RIGHTS_EXECUTE | ComACLRights.COM_RIGHTS_EXECUTE_LOCAL | ComACLRights.COM_RIGHTS_ACTIVATE_LOCAL; //set local access. Always set execute 
       found = true; 
       break; 
      } 
     } 
     if(!found){ 
      //Network Service was not found. Add it to the ACL 
      SecurityIdentifier si = new SecurityIdentifier( 
       WellKnownSidType.NetworkServiceSid, null); 
      CommonAce ca = new CommonAce(
       AceFlags.None, 
       AceQualifier.AccessAllowed, 
       ComACLRights.COM_RIGHTS_EXECUTE | ComACLRights.COM_RIGHTS_EXECUTE_LOCAL | ComACLRights.COM_RIGHTS_ACTIVATE_LOCAL, 
       si, 
       false, 
       null); 
      acl.InsertAce(acl.Count, ca); 
     } 
     //re-set the ACL 
     sd.DiscretionaryAcl = acl; 

     byte[] binaryform = new byte[sd.BinaryLength]; 
     sd.GetBinaryForm(binaryform, 0); 
     Registry.SetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Ole", "DefaultAccessPermission", binaryform, RegistryValueKind.Binary); 
    } 
} 
+0

Tanto usted como Daniel parecen estar en el camino correcto. Todo sigue siendo tan doloroso, pero funciona. Me siento en contra de quién dar crédito. Pero parece que podrías usar los puntos más. :) – PerryJ

+1

De nada. Obtuve la mayoría de mis detalles rastreando el código fuente de DCOMPerm y analizando qué estaba haciendo (en C++). –

+0

Esto también podría ser útil: https://github.com/pauldotknopf/WindowsSDK7-Samples/tree/master/com/fundamentals/dcom/dcomperm – NTDLS

4

No pude encontrar ninguna forma .NET de hacer esto - puede usar la utilidad de línea de comandos MS DCOMPerm (también here) que es parte del SDK.

+1

Hay alguna posibilidad de que todavía hay una dcomper.exe por ahí? Ya no puedo encontrar una versión precompilada, los enlaces parecen estar muertos – Max

4

Esta información se almacena en HKCR\AppID\{Your-AppID}\LaunchPermission y AccessPermission. Estos son valores REG_BINARY que contienen descripciones de seguridad serializadas. No hay idea de si hay algo que proporcione un acceso conveniente a los de .NET ...

Más información sobre MSDN.

6

En circunstancias similares (configurando la seguridad DCOM desde una MSI) logré crear una solución que hace lo que quiero alterando los valores clave de registro en HKEY_CLASSES_ROOT \ AppID {APP-GUID-GOES-HERE}. Gracias a la respuesta de Arnout por ponerme en el camino correcto.

Específicamente, creé un método para editar los permisos de seguridad para objetos DCOM, que se almacenan en los valores de la clave de registro LaunchPermission y AccessPermission. Estos son descriptores de seguridad serializados, a los que se puede acceder pasando los datos binarios a través del RawSecurityDescriptor. Esta clase simplifica muchos de los detalles en una deliciosa forma .NET-y, pero aún tiene que atender todos los detalles lógicos con respecto a la ACL de Windows, y debe asegurarse de volver a escribir el descriptor de seguridad en el registro usando RawSecurityDescriptor.GetBinaryForm. .

El método que creé se llamaba EditOrCreateACE. Este método editará una ACE existente para una cuenta, o insertará una nueva, y se asegurará de que la máscara de acceso tenga los indicadores pasados ​​establecidos. Adjunto aquí como un ejemplo, esto no es en absoluto ninguna autoridad sobre la manera de tratar con él, ya que sé muy poco de ACL de Windows cosas aún:

// These are constants for the access mask on LaunchPermission. 
// I'm unsure of the exact constants for AccessPermission 
private const int COM_RIGHTS_EXECUTE = 1; 
private const int COM_RIGHTS_EXECUTE_LOCAL = 2; 
private const int COM_RIGHTS_EXECUTE_REMOTE = 4; 
private const int COM_RIGHTS_ACTIVATE_LOCAL = 8; 
private const int COM_RIGHTS_ACTIVATE_REMOTE = 16; 

void EditOrCreateACE(string keyname, string valuename, 
         string accountname, int mask) 
{ 
    // Get security descriptor from registry 
    byte[] keyval = (byte[]) Registry.GetValue(keyname, valuename, 
               new byte[] { }); 
    RawSecurityDescriptor sd; 
    if (keyval.Length > 0) { 
     sd = new RawSecurityDescriptor(keyval, 0); 
    } else { 
     sd = InitializeEmptySecurityDescriptor(); 
    } 
    RawAcl acl = sd.DiscretionaryAcl; 

    CommonAce accountACE = null; 

    // Look for the account in the ACL 
    int i = 0; 
    foreach (GenericAce ace in acl) { 
     if (ace.AceType == AceType.AccessAllowed) { 
      CommonAce c_ace = ace as CommonAce; 
      NTAccount account = 
       c_ace.SecurityIdentifier.Translate(typeof(NTAccount)) 
       as NTAccount; 
      if (account.Value.Contains(accountname)) { 
       accountACE = c_ace; 
      } 
      i++; 
     } 
    } 

    // If no ACE found for the given account, insert a new one at the end 
    // of the ACL, otherwise just set the mask 
    if (accountACE == null) { 
     SecurityIdentifier ns_account = 
      (new NTAccount(accountname)).Translate(typeof(SecurityIdentifier)) 
      as SecurityIdentifier; 
     CommonAce ns = new CommonAce(AceFlags.None, AceQualifier.AccessAllowed, 
            mask, ns_account, false, null); 
     acl.InsertAce(acl.Count, ns); 
    } else { 
     accountACE.AccessMask |= mask; 
    } 

    // Write security descriptor back to registry 
    byte[] binarySd = new byte[sd.BinaryLength]; 
    sd.GetBinaryForm(binarySd, 0); 
    Registry.SetValue(keyname, valuename, binarySd); 
} 

private static RawSecurityDescriptor InitializeEmptySecurityDescriptor() 
{ 
    var localSystem = 
     new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null); 
    var new_sd = 
     new RawSecurityDescriptor(ControlFlags.DiscretionaryAclPresent, 
            localSystem, localSystem, null, 
            new RawAcl(GenericAcl.AclRevision, 1)); 
    return new_sd; 
} 

Ten en cuenta que este código no es de ningún significa perfecto. Si falta todo el valor de la clave de registro para estas ACL en el registro, la ACL que se sintetiza SÓLO otorgará acceso a la cuenta pasada y nada más. También estoy seguro de que hay muchas condiciones de error que no he manejado correctamente y detalles que he pasado por alto. De nuevo, es un ejemplo de cómo lidiar con DCOM ACL en .NET.

+0

¡Yikes! Solo noté tu respuesta, lo siento por eso. Lo probaré, ojalá pronto, y me pondré en contacto contigo. Parece que necesitamos una biblioteca completa al respecto. – PerryJ

0

me encontré con esta solución de trabajo:

public static void SetUp() 
    { 
     SetCOMSercurityAccess("DefaultAccessPermission"); 
     SetCOMSercurityAccess("DefaultLaunchPermission"); 
    } 
    private static void SetCOMSercurityAccess(string regKey) 
    { 
     //This is the magic permission! 
     byte[] binaryform = new string[] 
     { 
      "01","00","04","80","80","00","00","00","90","00","00","00","00","00","00","00","14","00","00","00","02","00","6c","00","04", 
      "00","00","00","00","00","14","00","1f","00","00","00","01","01","00","00","00","00","00","05","12","00","00","00","00","00", 
      "24","00","0b","00","00","00","01","05","00","00","00","00","00","05","15","00","00","00","a3","53","d8","c8","94","bd","63", 
      "84","88","bf","fa","cf","a7","2b","00","00","00","00","18","00","1f","00","00","00","01","02","00","00","00","00","00","05", 
      "20","00","00","00","20","02","00","00","00","00","14","00","1f","00","00","00","01","01","00","00","00","00","00","05","04", 
      "00","00","00","01","02","00","00","00","00","00","05","20","00","00","00","20","02","00","00","01","02","00","00","00","00", 
      "00","05","20","00","00","00","20","02","00","00" 
     }.Select(o=> Convert.ToByte(o,16)).ToArray(); 
     Registry.SetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Ole", regKey, binaryform, RegistryValueKind.Binary); 
    } 

En caso de que ayudar a los demás ...