Compartir a través de


Moniker de elevación COM

El moniker de elevación COM permite a las aplicaciones que se ejecutan bajo el control de cuentas de usuario (UAC) activar clases COM con privilegios elevados. Para obtener más información, vea Centrarse en privilegios mínimos.

Cuándo usar el Moniker de elevación

El moniker de elevación se usa para activar una clase COM para realizar una función específica y limitada que requiere privilegios elevados, como cambiar la fecha y hora del sistema.

La elevación requiere la participación tanto de una clase COM como de su cliente. La clase COM debe configurarse para admitir la elevación anotando su entrada del Registro, como se describe en la sección Requisitos. El cliente COM debe solicitar elevación mediante el moniker de elevación.

El moniker de elevación no está pensado para proporcionar compatibilidad con la aplicación. Por ejemplo, si desea ejecutar una aplicación COM heredada como WinWord como un servidor con privilegios elevados, debe configurar el ejecutable del cliente COM para requerir elevación, en lugar de activar la clase de la aplicación heredada con el moniker de elevación. Cuando el cliente COM con privilegios elevados llama a CoCreateInstance mediante el CLSID de la aplicación heredada, el estado elevado del cliente fluirá al proceso del servidor.

No todas las funciones COM son compatibles con la elevación. La funcionalidad que no funcionará incluye:

  • La elevación no fluye desde un cliente a un servidor COM remoto. Si un cliente activa un servidor COM remoto con el moniker de elevación, el servidor no se elevará, aunque admita la elevación.
  • Si una clase COM con privilegios elevados usa la suplantación durante una llamada COM, podría perder sus privilegios elevados durante la suplantación.
  • Si un servidor COM con privilegios elevados registra una clase en la tabla de objetos en ejecución (ROT), la clase no estará disponible para clientes sin privilegios elevados.
  • Un proceso con privilegios elevados mediante el mecanismo UAC no carga clases por usuario durante las activaciones COM. En el caso de las aplicaciones COM, esto significa que las clases COM de la aplicación deben instalarse en el subárbol del Registro de HKEY_LOCAL_MACHINE si la aplicación se va a usar tanto mediante cuentas con privilegios como con privilegios. Las clases COM de la aplicación solo deben instalarse en el subárbol HKEY_USERS si las cuentas con privilegios nunca usan la aplicación.
  • No se permite arrastrar y colocar desde aplicaciones con privilegios elevados a aplicaciones con privilegios elevados.

Requisitos

Para usar el moniker de elevación para activar una clase COM, la clase debe configurarse para ejecutarse como el usuario de inicio o la identidad de aplicación "Activar como activador". Si la clase está configurada para ejecutarse en cualquier otra identidad, la activación devuelve el error CO_E_RUNAS_VALUE_MUST_BE_AAA.

La clase también debe anotarse con un nombre para mostrar "descriptivo" compatible con la interfaz de usuario multilingüe (MUI). Esto requiere la siguiente entrada del Registro:

HKEY_LOCAL_MACHINE\Software\Classes\CLSID
   {CLSID}
      LocalizedString = displayName

Si falta esta entrada, la activación devuelve el error CO_E_MISSING_DISPLAYNAME. Si falta el archivo MUI, se devuelve el código de error de la función RegLoadMUIStringW .

Opcionalmente, para especificar un icono de aplicación que va a mostrar la interfaz de usuario de UAC, agregue la siguiente clave del Registro:

HKEY_LOCAL_MACHINE\Software\Classes\CLSID
   {CLSID}
      Elevation
         IconReference = applicationIcon

IconReference usa el mismo formato que LocalizedString:

@pathtobinary,-resourcenumber

Además, el componente COM debe firmarse para que se muestre el icono.

La clase COM también debe anotarse como LUA-Enabled. Esto requiere la siguiente entrada del Registro:

HKEY_LOCAL_MACHINE\Software\Classes\CLSID
   {CLSID}
      Elevation
         Enabled = 1

Si falta esta entrada, la activación devuelve el error CO_E_ELEVATION_DISABLED.

Tenga en cuenta que estas entradas deben existir en el subárbol HKEY_LOCAL_MACHINE, no en el subárbol HKEY_CURRENT_USER o HKEY_USERS. Esto evita que los usuarios elevan las clases COM que tampoco tienen los privilegios para registrarse.

Moniker de elevación y la interfaz de usuario de elevación

Si el cliente ya tiene privilegios elevados, el uso del moniker de elevación no hará que se muestre la interfaz de usuario de elevación.

Cómo usar el Moniker de elevación

El moniker de elevación es un moniker COM estándar, similar a los monikers de sesión, partición o cola. Dirige una solicitud de activación a un servidor especificado con el nivel de elevación especificado. El CLSID que se va a activar aparece en la cadena de moniker.

El moniker de elevación admite los siguientes tokens de nivel de ejecución:

  1. Administrador
  2. Highest (el más alto)

La sintaxis para esto es la siguiente:

Elevation:Administrator!new:{guid}
Elevation:Highest!new:{guid}

La sintaxis anterior usa el moniker "new" para devolver una instancia de la clase COM especificada por guid. Tenga en cuenta que el moniker "nuevo" usa internamente la interfaz IClassFactory para obtener un objeto de clase y, a continuación, llama a IClassFactory::CreateInstance en él.

El moniker de elevación también se puede usar para obtener un objeto de clase, que implementa IClassFactory. A continuación, el autor de la llamada llama a CreateInstance para obtener una instancia de objeto. La sintaxis para esto es la siguiente:

Elevation:Administrator!clsid:{guid}

Código de ejemplo

En el ejemplo de código siguiente se muestra cómo usar el moniker de elevación. Se supone que ya ha inicializado COM en el subproceso actual.

HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLSID rclsid, REFIID riid, __out void ** ppv)
{
    BIND_OPTS3 bo;
    WCHAR  wszCLSID[50];
    WCHAR  wszMonikerName[300];

    StringFromGUID2(rclsid, wszCLSID, sizeof(wszCLSID)/sizeof(wszCLSID[0])); 
    HRESULT hr = StringCchPrintf(wszMonikerName, sizeof(wszMonikerName)/sizeof(wszMonikerName[0]), L"Elevation:Administrator!new:%s", wszCLSID);
    if (FAILED(hr))
        return hr;
    memset(&bo, 0, sizeof(bo));
    bo.cbStruct = sizeof(bo);
    bo.hwnd = hwnd;
    bo.dwClassContext  = CLSCTX_LOCAL_SERVER;
    return CoGetObject(wszMonikerName, &bo, riid, ppv);
}

BIND_OPTS3 es nuevo en Windows Vista. Se deriva de BIND_OPTS2.

La única adición es un campo HWND , hwnd. Este identificador representa una ventana que se convierte en el propietario de la interfaz de usuario de Elevación, si procede.

Si hwnd es NULL, COM llamará a GetActiveWindow para buscar un identificador de ventana asociado al subproceso actual. Este caso puede producirse si el cliente es un script, que no puede rellenar una estructura de BIND_OPTS3 . En este caso, COM intentará usar la ventana asociada al subproceso de script.

Elevación sobre el hombro (OTS)

La elevación por encima del hombro (OTS) hace referencia al escenario en el que un cliente ejecuta un servidor COM con las credenciales de un administrador en lugar de sus propias. (El término "sobre el hombro" significa que el administrador está vigilando el hombro del cliente a medida que el cliente ejecuta el servidor).

Este escenario puede causar un problema para las llamadas COM al servidor, ya que es posible que el servidor no llame a CoInitializeSecurity explícitamente (es decir, mediante programación) o implícitamente (es decir, mediante declaración, mediante el registro). Para estos servidores, COM calcula un descriptor de seguridad que solo permite que SELF, SYSTEM y Builtin\Administrators realicen llamadas COM al servidor. Esta disposición no funcionará en escenarios de OTS. En su lugar, el servidor debe llamar a CoInitializeSecurity, ya sea explícita o implícitamente, y especificar una ACL que incluya el SID del grupo INTERACTIVO y SYSTEM.

En el ejemplo de código siguiente se muestra cómo crear un descriptor de seguridad (SD) con el SID del grupo INTERACTIVO.

BOOL GetAccessPermissionsForLUAServer(SECURITY_DESCRIPTOR **ppSD)
{
// Local call permissions to IU, SY
    LPWSTR lpszSDDL = L"O:BAG:BAD:(A;;0x3;;;IU)(A;;0x3;;;SY)";
    SECURITY_DESCRIPTOR *pSD;
    *ppSD = NULL;

    if (ConvertStringSecurityDescriptorToSecurityDescriptorW(lpszSDDL, SDDL_REVISION_1, (PSECURITY_DESCRIPTOR *)&pSD, NULL))
    {
        *ppSD = pSD;
        return TRUE;
    }

    return FALSE;
}

En el ejemplo de código siguiente se muestra cómo llamar implícitamente a CoInitializeSecurity con sd del ejemplo de código anterior:

// hKey is the HKCR\AppID\{GUID} key
BOOL SetAccessPermissions(HKEY hkey, PSECURITY_DESCRIPTOR pSD)
{
    BOOL bResult = FALSE;
    DWORD dwLen = GetSecurityDescriptorLength(pSD);
    LONG lResult;
    lResult = RegSetValueExA(hkey, 
        "AccessPermission",
        0,
        REG_BINARY,
        (BYTE*)pSD,
        dwLen);
    if (lResult != ERROR_SUCCESS) goto done;
    bResult = TRUE;
done:
    return bResult;
}

En el ejemplo de código siguiente se muestra cómo llamar explícitamente a CoInitializeSecurity con el SD anterior:

// Absolute SD values
PSECURITY_DESCRIPTOR pAbsSD = NULL;
DWORD AbsSdSize = 0;
PACL  pAbsAcl = NULL;
DWORD AbsAclSize = 0;
PACL  pAbsSacl = NULL;
DWORD AbsSaclSize = 0;
PSID  pAbsOwner = NULL;
DWORD AbsOwnerSize = 0;
PSID  pAbsGroup = NULL;
DWORD AbsGroupSize = 0;

MakeAbsoluteSD (
    pSD,
    pAbsSD,
    &AbsSdSize,
    pAbsAcl,
    &AbsAclSize,
    pAbsSacl,
    &AbsSaclSize,
    pAbsOwner,
    &AbsOwnerSize,
    pAbsGroup,
    &AbsGroupSize
);

if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
    pAbsSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, AbsSdSize);
    pAbsAcl = (PACL)LocalAlloc(LMEM_FIXED, AbsAclSize);
    pAbsSacl = (PACL)LocalAlloc(LMEM_FIXED, AbsSaclSize);
    pAbsOwner = (PSID)LocalAlloc(LMEM_FIXED, AbsOwnerSize);
    pAbsGroup = (PSID)LocalAlloc(LMEM_FIXED, AbsGroupSize);

    if ( ! (pAbsSD && pAbsAcl && pAbsSacl && pAbsOwner && pAbsGroup))
    {
        hr = E_OUTOFMEMORY;
        goto Cleanup;
    }
    if ( ! MakeAbsoluteSD(
        pSD,
        pAbsSD,
        &AbsSdSize,
        pAbsAcl,
        &AbsAclSize,
        pAbsSacl,
        &AbsSaclSize,
        pAbsOwner,
        &AbsOwnerSize,
        pAbsGroup,
        &AbsGroupSize
        ))
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        goto Cleanup;
    }
}
else
{
    hr = HRESULT_FROM_WIN32(GetLastError());
    goto Cleanup;
}

// Call CoInitializeSecurity .

Permisos COM y etiquetas de acceso obligatorias

Windows Vista presenta la noción de etiquetas de acceso obligatorias en descriptores de seguridad. La etiqueta determina si los clientes pueden obtener acceso de ejecución a un objeto COM. La etiqueta se especifica en la parte de la lista de control de acceso del sistema (SACL) del descriptor de seguridad. En Windows Vista, COM admite la etiqueta SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP. Las SACL de los permisos COM se omiten en los sistemas operativos antes de Windows Vista.

A partir de Windows Vista, dcomcnfg.exe no admite cambiar el nivel de integridad (IL) en permisos COM. Debe establecerse mediante programación.

En el ejemplo de código siguiente se muestra cómo crear un descriptor de seguridad COM con una etiqueta que permite solicitudes de inicio o activación de todos los clientes low IL. Tenga en cuenta que las etiquetas son válidas para los permisos de inicio/activación y llamada. Por lo tanto, es posible escribir un servidor COM que no permita el inicio, la activación o las llamadas desde clientes con un il determinado. Para obtener más información sobre los niveles de integridad, vea la sección "Descripción del mecanismo de integridad de Windows Vista" en Descripción y funcionamiento en modo protegido de Internet Explorer.

BOOL GetLaunchActPermissionsWithIL (SECURITY_DESCRIPTOR **ppSD)
{
// Allow World Local Launch/Activation permissions. Label the SD for LOW IL Execute UP
    LPWSTR lpszSDDL = L"O:BAG:BAD:(A;;0xb;;;WD)S:(ML;;NX;;;LW)";
    if (ConvertStringSecurityDescriptorToSecurityDescriptorW(lpszSDDL, SDDL_REVISION_1, (PSECURITY_DESCRIPTOR *)&pSD, NULL))
    {
        *ppSD = pSD;
        return TRUE;
    }
}

BOOL SetLaunchActPermissions(HKEY hkey, PSECURITY_DESCRIPTOR pSD)
{
    
    BOOL bResult = FALSE;
    DWORD dwLen = GetSecurityDescriptorLength(pSD);
    LONG lResult;
    lResult = RegSetValueExA(hkey, 
        "LaunchPermission",
        0,
        REG_BINARY,
        (BYTE*)pSD,
        dwLen);
    if (lResult != ERROR_SUCCESS) goto done;
    bResult = TRUE;
done:
    return bResult;
};

CoCreateInstance y niveles de integridad

El comportamiento de CoCreateInstance ha cambiado en Windows Vista para evitar que los clientes de IL bajos se enlacen a servidores COM de forma predeterminada. El servidor debe permitir explícitamente estos enlaces especificando sacl. Los cambios en CoCreateInstance son los siguientes:

  1. Al iniciar un proceso de servidor COM, el IL del token de proceso del servidor se establece en el IL del token de cliente o servidor, lo que sea menor.
  2. De forma predeterminada, COM impedirá que los clientes de IL bajos se enlacen a instancias en ejecución de cualquier servidor COM. Para permitir el enlace, el descriptor de seguridad de inicio/activación de un servidor COM debe contener una SACL que especifique la etiqueta low IL (consulte la sección anterior del código de ejemplo para crear este descriptor de seguridad).

Servidores elevados y registros ROT

Si un servidor COM desea registrarse en la tabla de objetos en ejecución (ROT) y permitir que cualquier cliente acceda al registro, debe usar la marca ROTFLAGS_ALLOWANYCLIENT. Un servidor COM "Activar como activador" no puede especificar ROTFLAGS_ALLOWANYCLIENT porque el administrador de control de servicios DCOM (DCOMSCM) aplica una comprobación de suplantación de identidad en esta marca. Por lo tanto, en Windows Vista, COM agrega compatibilidad con una nueva entrada del Registro que permite al servidor estipular que sus registros ROT estén disponibles para cualquier cliente:

HKEY_LOCAL_MACHINE\Software\Classes\AppID
   {APPID}
      ROTFlags

El único valor válido para esta entrada de REG_DWORD es:

ROTREGFLAGS_ALLOWANYCLIENT 0x1

La entrada debe existir en el subárbol HKEY_LOCAL_MACHINE .

Esta entrada proporciona un servidor "Activar como activador" con la misma funcionalidad que ROTFLAGS_ALLOWANYCLIENT proporciona para un servidor RunAs.

Seguridad en COM

Descripción y trabajo con el modo protegido de Internet Explorer [puede estar en inglés]