CreateNamedPipe sin PIPE_REJECT_REMOTE_CLIENTS

Estoy tratando de crear una tubería con nombre dúplex usando la API de Windows CreateNamedPipe para usar para IPC entre mi extensión de shell y mi aplicación de escritorio principal.

Hay un indicador que puede pasar esa función para Vista y superior que evita las conexiones remotas (PIPE_REJECT_REMOTE_CLIENTS). Por lo que entiendo, eso significa que la tubería solo se puede conectar en la misma máquina. ¿Alguien sabe cómo obtener la misma funcionalidad en versiones anteriores de Windows? He intentado crear un SECURITY_ATTRIBUTES object con el siguiente código, pero no estoy completamente seguro de que funcione correctamente:

static bool GetLocalMachineOnlySecurityAttributes (SECURITY_ATTRIBUTES& sa)
{
    PSID plocalsid = NULL;
    SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_LOCAL_SID_AUTHORITY;
    if(!::AllocateAndInitializeSid (&SIDAuthWorld, 1, SECURITY_LOCAL_RID, 0, 0, 0, 0, 0, 0, 0, &plocalsid))
        return false;

    EXPLICIT_ACCESS ea = {0};
    ea.grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
    ea.grfAccessMode = SET_ACCESS;
    ea.grfInheritance = NO_INHERITANCE;
    ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea.Trustee.ptstrName  = reinterpret_cast<LPWSTR>(plocalsid);

    PACL acl = NULL;
    if(!::SetEntriesInAcl (1, &ea, NULL, &acl))
        return false;

    //PSECURITY_DESCRIPTOR sd = reinterpret_cast<PSECURITY_DESCRIPTOR>(::LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH));
    static SECURITY_DESCRIPTOR sd = {0};
    if(!::InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION))
        return false;
    if(!::SetSecurityDescriptorDacl(&sd, TRUE, acl, FALSE))
        return false;

    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = &sd;
    sa.bInheritHandle = FALSE;
    return true;
}

Si hay alguien por ahí que pueda decirme si estoy haciendo lo correcto o en algún lugar puedo buscar una explicación definitiva de SECURITY_ATTRIBUTES, le estaría muy agradecido.

preguntado el 12 de junio de 12 a las 21:06

1 Respuestas

De hecho, puede evitar las conexiones remotas creando una lista de control de acceso discrecional (DACL) adecuada para la tubería.

Su código está intentando pero fallando en hacer eso, la primera razón está en esta línea:

if(!::SetEntriesInAcl (1, &ea, NULL, &acl)) 

SetEntriesInAcl devuelve un código DWORD, no un BOOL: en caso de éxito, el código devuelto es ERROR_SUCCESS, que tiene el valor 0L, por lo que su función siempre sale en este punto, dejando la estructura SECURITY_ATTRIBUTES vacía.

Su código también pierde memoria, ya que no puede desasignar los búferes creados por algunas de las API, incluido SetEntriesInAcl. Te sugiero que uses el ejemplo en MSDN como una guía para asegurarse de hacer toda la limpieza necesaria.

Volviendo más a la estrategia de su código, actualmente está tratando de resolver su problema utilizando una única entrada de control de acceso (ACE) que permite todo el acceso para el grupo de seguridad local. Debido a la forma en que funcionan las DACL, esa no es la forma correcta de hacerlo ... en su lugar, debe denegar el acceso remoto, es decir, incluirlo en la lista negra, en lugar de intentar incluir el acceso local en la lista blanca. Esto se debe al menos a dos razones:

  • con un solo ACE, todos los que pueden acceder a la tubería tienen exactamente los mismos derechos de acceso: ha perdido la capacidad de controlar la seguridad de la tubería más de cerca. Como mínimo, normalmente desea asegurarse de que solo el servidor de canalización previsto pueda crear nuevas instancias de la canalización y también restringir la capacidad de cambiar la seguridad en la canalización.
  • las circunstancias exactas en las que se otorgan tokens de acceso como miembros del grupo Local no están muy bien documentadas, y sospecho que la pertenencia a este grupo no se alinea precisamente con su requisito. La documentación de CreateNamedPipe establece explícitamente que para lograr el mismo resultado que PIPE_REJECT_REMOTE_CLIENTS en plataformas anteriores, debe negar acceso a la RED.

Por lo tanto, su código debe modificarse para que pueda crear una DACL que contenga las siguientes ACE:

  1. Una ACE de "denegación" para el conocido grupo de identificadores de seguridad USUARIOS DE LA RED, que deniega todo acceso
  2. Un ACE "permitir" que permite que la aplicación que es el servidor de tubería cree instancias de la tubería
  3. Un ACE "permitir" que permite que la aplicación que es el cliente de la tubería lea y escriba en la tubería

El primero de estos es lo que impedirá el acceso remoto a la canalización, porque todos los tokens de inicio de sesión creados por los protocolos de acceso remoto, incluido el protocolo de canalización con nombre remoto basado en SMB, contienen automáticamente una pertenencia al grupo USUARIOS DE LA RED (el conocido SID S-1-5-2). Esta ACE de denegación debe venir antes que las ACE permitidas en la DACL.

No dice cuál de sus aplicaciones es el servidor de tubería y cuál el cliente. Tal vez no importe, si ambos se ejecutan en la sesión del usuario interactivo: en este caso, puede usar solo un ACE de permiso que otorga todo el acceso al SID para la sesión del usuario.

Sin más detalles de su requisito de seguridad, es difícil ser prescriptivo en cuanto a cómo debe configurar las ACE del servidor y del cliente. Sin embargo, es casi seguro que querrá restringir el derecho de acceso FILE_CREATE_PIPE_INSTANCE para que solo lo tenga el servidor de tubería.

Respondido el 14 de junio de 12 a las 13:06

¡Muchas gracias por su respuesta! Esa es mucha información. Arreglé las filtraciones como usted sugirió y arreglé el manejo de la devolución de SetEntriesInAcl. Para brindarle más información, mi aplicación de escritorio (solo una aplicación de interfaz gráfica de usuario simple) crea la tubería. La extensión del explorador es el cliente que se conecta a la tubería. Creo que mi mayor dificultad para completar la estructura SECURITY_ATTRIBUTES es la documentación, aunque inmensa, es intimidante para el novato. ¿Tiene alguna sugerencia sobre cómo crear estos ACE? ¿Tal vez el formato de cadena del descriptor de seguridad? - chico cpp

Además, de un vistazo, ¿puede decirme si estoy usando las banderas y los valores de herencia correctos para las diversas estructuras? Muchos ejemplos en la web combinan y combinan banderas de diferentes API al crear sus SECUITY_ATTRIBUTES - chico cpp

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.