Compartilhar via


Suporte para nomenclatura UNC e MUP

O provedor de UNC múltiplo (MUP) é um componente de modo kernel responsável por canalizar todos os acessos remotos ao sistema de arquivos usando um nome UNC (Universal Naming Convention, convenção universal de nomenclatura) para um redirecionador de rede (o provedor UNC) capaz de lidar com as solicitações do sistema de arquivos remoto. O MUP está envolvido quando um caminho de UNC é usado por um aplicativo, conforme ilustrado pelo exemplo a seguir, que pode ser executado a partir de uma linha de comando:

notepad \\server\public\readme.txt

O MUP não está envolvido durante uma operação que cria uma letra de unidade mapeada (o comando "NET USE", por exemplo). Essa operação é tratada pelo roteador de vários provedores (MPR) e uma DLL de provedor WNet de modo de usuário para o redirecionador de rede. No entanto, uma DLL do provedor WNet de modo de usuário pode se comunicar diretamente com um driver de redirecionador de rede de modo kernel durante essa operação.

No Microsoft Windows Server 2003, Windows XP e Windows 2000, as operações de arquivo remoto executadas em uma unidade mapeada que não representa uma unidade DFS (Distributed File System, sistema de arquivos distribuídos) não passam pelo MUP. Essas operações passam diretamente para o provedor de rede que processou o mapeamento de letra da unidade.

Para redirecionadores de rede que estão em conformidade com o modelo de redirecionador do Windows Vista, o MUP será envolvido mesmo quando uma unidade de rede mapeada for usada. As operações de arquivo executadas na unidade mapeada passam pelo MUP até o redirecionador de rede. Nesse caso, o MUP simplesmente passa a operação para o redirecionador de rede envolvido.

O MUP faz parte do binário mup.sys, que também inclui o cliente Microsoft DFS no Windows Server 2003, Windows XP e Windows 2000.

Um redirecionador de rede do kernel normalmente também terá uma DLL do provedor WNet no modo de usuário para oferecer suporte ao estabelecimento de conexões com recursos remotos (mapeamento de letras da unidade para recursos remotos, por exemplo). O MPR é uma DLL de modo de usuário que estabelece conexões de rede com base em consultas a provedores WNet. As chamadas para o MPR resultariam de qualquer um dos seguintes:

Um comando "net use x: \\server\share" emitido de um prompt de comando.

Uma conexão de letra de unidade de rede estabelecida por meio do Windows Explorer

Chamadas diretas para funções WNet.

Um redirecionador de rede deve se registrar no MUP para lidar com nomes UNC. Pode haver vários provedores UNC registrados no MUP. Esses provedores UNC podem ser um ou mais dos seguintes:

  • Mini-redirecionadores de rede baseados em RDBSS

  • Redirecionadores herdados não baseados em RDBSS

O MUP determina qual provedor pode manipular um caminho UNC em uma operação baseada em nome, normalmente uma solicitação IRP_MJ_CREATE. Isso é conhecido como "resolução de prefixo". Nas versões anteriores ao Windows Vista, a operação de resolução de prefixo tem duas finalidades:

  • A operação baseada em nome que resultou na resolução do prefixo é roteada para o provedor que reivindica o prefixo. Caso seja bem-sucedido, o MUP garante que as operações subsequentes baseadas em identificador (IRP_MJ_READ e IRP_MJ_WRITE, por exemplo) vão para o mesmo provedor ignorando completamente o MUP.

  • O provedor e o prefixo que ele reivindicou são inseridos em um cache de prefixo mantido pelo MUP. Para operações subsequentes baseadas em nome, o MUP usa o cache de prefixo para determinar se um provedor já reivindicou um prefixo antes de tentar executar uma resolução de prefixo. Cada entrada no cache de prefixo está sujeita a um tempo limite (conhecido como TTL) depois de ser adicionada ao cache. Uma entrada é descartada depois que o tempo limite expira, momento em que o MUP executará a resolução de prefixo novamente para o prefixo em questão em uma operação subsequente baseada em nome.

O MUP executa a resolução de prefixo emitindo a solicitação IOCTL_REDIR_QUERY_PATH para redirecionadores de rede registrados no MUP. Os buffers de entrada e saída para IOCTL_REDIR_QUERY_PATH são os seguintes:

Parâmetro disponível em Formato da estrutura de dados

Buffer de entrada

IrpSp-> Parameters.DeviceIoControl.Type3InputBuffer

QUERY_PATH_REQUEST

Buffer de saída

IRP->UserBuffer

QUERY_PATH_RESPONSE

A IOCTL e as estruturas de dados são definidas em ntifs.h. Os buffers são alocados do pool não paginado.

Os redirecionadores de rede só devem permitir remetentes no modo kernel dessa IOCTL, verificando se o membro RequesterMode da estrutura IRP é KernelMode.

O MUP usa a estrutura de dados QUERY_PATH_REQUEST para as informações da solicitação.

typedef struct _QUERY_PATH_REQUEST {
    ULONG                PathNameLength;
    PIO_SECURITY_CONTEXT SecurityContext;
    WCHAR                FilePathName[1];
} QUERY_PATH_REQUEST, *PQUERY_PATH_REQUEST;
Membro da estrutura Descrição

PathNameLength

O tamanho, em bytes, da cadeia de caracteres Unicode contida no membro FilePathName.

SecurityContext

Um ponteiro para o contexto de segurança.

FilePathName

Uma cadeia de caracteres Unicode terminada não NULL do formulário <server><share><path>. O tamanho da cadeia de caracteres, em bytes, é especificado pelo membro PathNameLength.

Os provedores UNC devem usar a estrutura de dados QUERY_PATH_RESPONSE para as informações de resposta.

typedef struct _QUERY_PATH_RESPONSE {
    ULONG  LengthAccepted;
} QUERY_PATH_RESPONSE, *PQUERY_PATH_RESPONSE;
Membro da estrutura Descrição

LengthAccepted

O tamanho, em bytes, do prefixo solicitado pelo provedor a partir do caminho da cadeia de caracteres Unicode especificado no membro FilePathName da estrutura QUERY_PATH_REQUEST.

Note que IOCTL_REDIR_QUERY_PATH é um METHOD_NEITHER IOCTL. Isso significa que os buffers de entrada e saída podem não estar no mesmo endereço. Um erro comum dos provedores UNC é presumir que o buffer de entrada e o buffer de saída são os mesmos e usar o ponteiro do buffer de entrada para fornecer a resposta.

Quando um provedor UNC recebe uma solicitação IOCTL_REDIR_QUERY_PATH, ele precisa determinar se pode processar o caminho UNC especificado no membro FilePathName da estrutura QUERY_PATH_REQUEST. Em caso afirmativo, é preciso atualizar o membro LengthAccepted da estrutura QUERY_PATH_RESPONSE com o tamanho, em bytes, do prefixo que solicitado e completar o IRP com STATUS_SUCCESS. Se o provedor não puder processar o caminho UNC especificado, ocorrerá falha na solicitação IOCTL_REDIR_QUERY_PATH com um código de erro NTSTATUS apropriado, e o membro LengthAccepted da estrutura QUERY_PATH_RESPONSE não será atualizado. Os provedores não devem modificar nenhum dos outros membros ou a cadeia de caracteres FilePathName sob nenhuma condição.

Se o nome do prefixo \\server\share não for reconhecido em resposta a um IRP_MJ_CREATE ou outros IRPs que estejam usando nomes UNC, o código NTSTATUS recomendado a ser retornado será um dos seguintes:

STATUS_BAD_NETWORK_PATH
O caminho de rede não pode ser localizado. O nome da máquina (\\server, por exemplo) não é válido ou o redirecionador de rede não pode resolver o nome da máquina (usando quaisquer mecanismos de resolução de nomes disponíveis).

STATUS_BAD_NETWORK_NAME
O nome de compartilhamento especificado não pode ser encontrado no servidor remoto. O nome da máquina (\\server, por exemplo) é válido, mas o nome de compartilhamento especificado não pode ser encontrado no servidor remoto.

STATUS_INSUFFICIENT_RESOURCES
Não havia recursos suficientes disponíveis para alocar memória para buffers.

STATUS_INVALID_DEVICE_REQUEST
Uma solicitação IOCTL_REDIR_QUERY_PATH só deve vir do MUP, e o modo solicitante do IRP deve ser sempre KernelMode. Esse código de erro será retornado se o modo solicitante do thread de chamada não for KernelMode.

STATUS_INVALID_PARAMETER
O membro PathNameLength na estrutura QUERY_PATH_REQUEST excede o tamanho máximo permitido, UNICODE_STRING_MAX_BYTES, para uma cadeia de caracteres Unicode.

STATUS_LOGON_FAILURE ou STATUS_ACCESS_DENIED
Se a operação de resolução de prefixo falhar devido a credenciais inválidas ou incorretas, o provedor deverá retornar o código de erro exato retornado pelo servidor remoto. Esses códigos de erro não devem ser traduzidos para STATUS_BAD_NETWORK_NAME ou STATUS_BAD_NETWORK_PATH. Códigos de erro como STATUS_LOGON_FAILURE e STATUS_ACCESS_DENIED servem como um mecanismo de feedback para o usuário, indicando o requisito de usar credenciais apropriadas. Esses códigos de erro também são usados em certos casos para solicitar credenciais automaticamente ao usuário. Sem esses códigos de erro, o usuário pode assumir que a máquina não está acessível.

Se o redirecionador de rede não conseguir resolver um prefixo, ele deverá retornar um código NTSTATUS que corresponda à semântica pretendida da lista de códigos NTSTATUS recomendados acima. Um redirecionador de rede não deverá retornar o erro encontrado real (STATUS_CONNECTION_REFUSED, por exemplo) diretamente ao MUP se o código NTSTATUS não for da lista acima.

O tamanho do prefixo solicitado pelo provedor depende de um provedor UNC individual. A maioria dos provedores geralmente reivindica a parte \\<servername>\<sharename > de um caminho do formulário \\<servername>\<sharename>\<path>. Por exemplo, se um provedor reivindicar \\server\public tendo em vista o caminho \\server\public\dir1\dir2, todas as operações baseadas em nome para o prefixo \\server\public (\server\public\file1, por exemplo) serão roteadas para esse provedor automaticamente sem qualquer resolução de prefixo, uma vez que o prefixo já está no cache de prefixos. No entanto, um caminho com o prefixo \server\marketing\presentation passará pela resolução de prefixos.

Se um redirecionador de rede reivindicar um nome de servidor (\\server, por exemplo), todas as solicitações de compartilhamentos nesse servidor serão passadas para esse redirecionador de rede. Esse comportamento só será aceitável se não houver possibilidade de outro compartilhamento no mesmo servidor ser acessado por um redirecionador de rede diferente. Por exemplo, um redirecionador de rede que reivindica \\server de um caminho UNC impedirá o acesso de outros redirecionadores de rede a outros compartilhamentos no servidor (acesso WebDAV a \\server\web, por exemplo).

Qualquer redirecionador de rede herdado (não baseado no uso de RDBSS) que se registra como um provedor UNC com MUP chamando FsRtlRegisterUncProvider receberá a solicitação IOCTL_REDIR_QUERY_PATH.

Um mini-redirecionador de rede que indica suporte como um provedor UNC receberá essa declaração de prefixo como se fosse uma chamada IRP_MJ_CREATE. Essa solicitação de criação é semelhante a uma chamada CreateFile com o sinalizador FILE_CREATE_TREE_CONNECTION definido. Um mini-redirecionador de rede não receberá a declaração de prefixo como uma chamada para MRxLowIOSubmit[LOWIO_OP_IOCTL]. Para uma declaração de prefixo, RDBSS enviará uma solicitação MRxCreateSrvCall para o redirecionador de rede seguido por uma chamada para MRxSrvCallWinnerNotify e MRxCreateVNetRoot. Quando um mini-redirecionador de rede se registrar com RDBSS, a tabela de despacho de driver para o mini-redirecionador de rede será copiada pelo RDBSS para apontar para pontos de entrada RDBSS internos. Em seguida, o RDBSS recebe o IOCTL_REDIR_QUERY_PATH internamente para o mini-redirecionador de rede e chama MRxCreateSrvCall, MRxSrvCallWinnerNotify e MRxCreateVNetRoot. O IRP IOCTL_REDIR_QUERY_PATH original estará contido na estrutura RX_CONTEXT passada para a rotina MRxCreateSrvCall. Além disso, os seguintes membros no RX_CONTEXT passado para MRxCreateSrvCall serão modificados:

O membro MajorFunction será definido como IRP_MJ_CREATE mesmo que o IRP original seja IRP_MJ_DEVICE_CONTROL.

O membro PrefixClaim.SuppliedPathName.Buffer será definido como FilePathName da estrutura QUERY_PATH_REQUEST.

O membro PrefixClaim.SuppliedPathName.Length será definido como o membro PathNameLength da estrutura QUERY_PATH_REQUEST.

O membro Create.NtCreateParameters.SecurityContext está definido como o membro SecurityContext da estrutura QUERY_PATH_REQUEST.

O membro Create.ThisIsATreeConnectOpen está definido como TRUE.

O membro Create.Flags tem o conjunto de bits RX_CONTEXT_CREATE_FLAG_UNC_NAME.

Se o mini-redirecionador de rede quiser ver detalhes da declaração de prefixo, ele poderá ler esses membros no RX_CONTEXT passado para MRxCreateSrvCall. Caso contrário, ele só poderá tentar se conectar ao compartilhamento do servidor e retornar STATUS_SUCCESS se a chamada MRxCreateSrvCall for bem-sucedida. O RDBSS fará a declaração de prefixo em nome do mini-redirecionador de rede.

Há um caso em que um mini-redirecionador de rede poderia receber essa IOCTL diretamente. Um mini-redirecionador de rede poderia salvar uma cópia da tabela de despacho de driver antes de inicializar e registrar com RDBSS. Depois de chamar RxRegisterMinirdr para se registrar com RDBSS, o mini-redirecionador de rede pode salvar uma cópia dos novos pontos de entrada da tabela de despacho de driver instalados pelo RDBSS e restaurar sua tabela de despacho de driver original. A tabela de despacho de driver restaurada precisaria ser modificada para que, depois de verificar o IRP recebido para aqueles de interesse para o mini-redirecionador de rede, a chamada seja encaminhada para os pontos de entrada de despacho do driver RDBSS. O RDBSS copiará a tabela de despacho de driver de um mini-redirecionador de rede quando o driver inicializar o RDBSS e chamar RxRegisterMinrdr. Um mini-redirecionador de rede que se vincula a rdbsslib.lib deve salvar sua tabela de despacho de driver original antes de chamar RxDriverEntry da rotina DriverEntry para inicializar a biblioteca estática de RDBSS e restaurar a tabela de despacho de driver após chamar RxRegisterMinrdr. Isso ocorre porque o RDBSS copia pela tabela de despacho do mini-redirecionador de rede nas rotinas RxDriverEntry e RxRegisterMinrdr.

A ordem na qual os provedores são consultados durante a resolução de prefixo é controlada pelo valor de registro REG_SZ ProviderOrder armazenado com a seguinte chave:

HKLM\System\CurrentControlSet\Control\NetworkProvider\Order

Os nomes de provedores individuais no valor do registro ProviderOrder são separados por vírgulas, sem espaço em branco à esquerda ou à direita.

Por exemplo, esse valor pode conter a cadeia de caracteres:

RDPNP,LanmanWorkstation,WebClient

Dado o caminho UNC \\<server>\<share>\<path>, o MUP emitirá uma solicitação de resolução de prefixo se o prefixo (\\server\share ou \\server, por exemplo) não for encontrado no cache de prefixo do MUP. O MUP envia uma solicitação de resolução de prefixo para cada provedor na seguinte ordem até que um provedor solicite o prefixo (ou todos os provedores tenham sido consultados):

  1. Cliente TS (RDPNP)

  2. Redirecionador SMB (LanmanWorkstation)

  3. Redirecionador WebDAV (WebClient)

As alterações no valor do registro ProviderOrder exigem uma reinicialização para entrar em vigor no MUP no Windows Server 2003, Windows XP e Windows 2000.

O MUP usa cada nome de provedor listado para localizar a chave do registro do provedor na seguinte chave do registro:

HKLM\System\CurrentControlSet\Services\<ProviderName>

Em seguida, o MUP lê o valor DeviceName na subchave NetworkProvider para localizar o nome do dispositivo com o qual o provedor se registrará. Quando o provedor realmente se registra, o MUP faz a correspondência do nome do dispositivo passado com a lista de nomes de dispositivos de provedores conhecidos e coloca o provedor em uma lista ordenada para fins de resolução de prefixos. A ordem dos provedores nesta lista se baseia na ordem especificada no valor do registro ProviderOrder discutido acima.

Observe que essa ordem de provedor também é honrada pelo MPR (Multiple Provider Router, roteador de vários fornecedores), a DLL de modo de usuário que estabelece conexões de rede com base em consultas a provedores WNet.

Antes do Windows Server 2003 com Service Pack 1 e do Windows XP com Service Pack 2, o comportamento do MUP era emitir solicitações de resolução de prefixo para todos os provedores "em paralelo" na ordem especificada no valor do registro ProviderOrder e, em seguida, aguardar que todos os provedores concluíssem a operação de resolução de prefixo. Assim, mesmo que o primeiro provedor tenha reivindicado o prefixo, o MUP ainda aguarda que todos os outros provedores concluam a operação de resolução de prefixo. Quando vários provedores respondem com uma declaração de prefixo, o MUP seleciona o provedor com base na ordem especificada no valor do registro ProviderOrder.

No Windows XP Service Pack 2 e posterior e no Windows Server 2003 Service Pack 1 e posterior, esse comportamento foi ligeiramente alterado. O MUP emite a solicitação de resolução de prefixo em série e interrompe assim que o primeiro provedor reivindica o prefixo. Assim, no exemplo acima, se RDPNP reivindicar um prefixo, o MUP não chamará os redirecionadores SMB ou WebDAV.

A principal razão pela qual esse comportamento foi alterado é que um esquema de "resolução de prefixo serial" impede que casos de um redirecionador de rede com prioridade mais baixa no valor ProviderOrder causem problemas de desempenho para um redirecionador de rede de prioridade mais alta no valor ProviderOrder. Por exemplo, considere um servidor remoto, com um firewall instalado, configurado para bloquear certos tipos de pacote TCP/IP (acesso a HTTP, por exemplo), mas para permitir outros (acesso SMB, por exemplo). Nesse caso, mesmo que o redirecionador de rede SMB esteja configurado como o primeiro provedor no valor ProviderOrder e reivindique o prefixo rapidamente, o redirecionador WebDAV pode atrasar significativamente a conclusão da resolução do prefixo aguardando o tempo limite da conexão TCP.