Share via


Prise en charge du nommage UNC et du MUP

Le fournisseur UNC multiple (MUP) est un composant en mode noyau responsable de la chaîne de tous les accès au système de fichiers à distance utilisant un nom UNC (Universal Naming Convention) vers un redirecteur réseau (le fournisseur UNC) capable de traiter les requêtes du système de fichiers à distance. MUP intervient lorsqu'un chemin UNC est utilisé par une application, comme l'illustre l'exemple suivant, qui pourrait être exécuté à partir d'une ligne de commande :

notepad \\server\public\readme.txt

Le MUP n'intervient pas lors d'une opération de création d'une lettre de lecteur mappée (la commande « NET USE », par exemple). Cette opération est gérée par le routeur à fournisseurs multiples (MPR) et une DLL de fournisseur WNet en mode utilisateur pour le redirecteur de réseau. Toutefois, une DLL de fournisseur WNet en mode utilisateur peut communiquer directement avec un pilote de redirecteur réseau en mode noyau pendant cette opération.

Sous Microsoft Windows Server 2003, Windows XP et Windows 2000, les opérations de fichiers distants effectuées sur un lecteur mappé qui ne représente pas un lecteur DFS (Distributed File System) ne passent pas par MUP. Ces opérations vont directement au fournisseur de réseau qui a géré le mappage des lettres de lecteur.

Pour les redirecteurs réseau conformes au modèle de redirecteur de Windows Vista, MUP est impliqué même lorsqu'un lecteur réseau mappé est utilisé. Les opérations de fichiers effectuées sur le lecteur mappé passent par le MUP pour atteindre le redirecteur réseau. Notez que dans ce cas, MUP transmet simplement l'opération au redirecteur réseau concerné.

MUP fait partie du binaire mup.sys, qui comprend également le client Microsoft DFS dans Windows Server 2003, Windows XP et Windows 2000.

Un redirecteur réseau du noyau dispose normalement aussi d'une DLL de fournisseur WNet en mode utilisateur pour établir des connexions avec des ressources distantes (mappage de lettres de lecteur à des ressources distantes, par exemple). Le MPR est une DLL en mode utilisateur qui établit des connexions réseau sur la base de requêtes adressées aux fournisseurs WNet. Les appels au MPR résulteraient de l'un des éléments suivants :

Un « net use x : \\Nserver\Nshare » émise à partir d'une invite de commande.

Une connexion par lettre de lecteur réseau établie à partir de l'Explorateur Windows.

Appels directs aux fonctions WNet.

Un redirecteur réseau doit s'enregistrer auprès de MUP pour gérer les noms UNC. Plusieurs fournisseurs UNC peuvent être enregistrés auprès de MUP. Ces fournisseurs UNC peuvent être un ou plusieurs des éléments suivants :

  • Mini-redirecteurs de réseau basés sur RDBSS

  • Redirecteurs traditionnels non basés sur RDBSS

Le MUP détermine quel fournisseur peut traiter un chemin UNC dans une opération basée sur le nom, généralement une requête IRP_MJ_CREATE. C'est ce qu'on appelle la « résolution de préfixe ». Avant Windows Vista, l'opération de résolution de préfixe avait deux objectifs :

  • L'opération basée sur le nom qui a abouti à la résolution du préfixe est acheminée vers le fournisseur qui revendique le préfixe. En cas de succès, le MUP veille à ce que les opérations ultérieures basées sur le handle (IRP_MJ_READ et IRP_MJ_WRITE, par exemple) aillent au même fournisseur en contournant complètement le MUP.

  • Le fournisseur et le préfixe qu'il a revendiqué sont enregistrés dans un cache de préfixes géré par le MUP. Pour les opérations ultérieures basées sur les noms, le MUP utilise ce cache de préfixes pour déterminer si un fournisseur a déjà réclamé un préfixe avant de tenter d'effectuer une résolution de préfixes. Chaque entrée dans ce cache de préfixes est soumise à un délai d'attente (appelé TTL) une fois qu'elle a été ajoutée au cache. Une entrée est supprimée à l'expiration de ce délai, après quoi le MUP effectuera à nouveau une résolution de préfixe pour ce préfixe lors d'une opération ultérieure basée sur le nom.

MUP effectue la résolution des préfixes en émettant une requête IOCTL_REDIR_QUERY_PATH aux redirecteurs de réseau enregistrés auprès de MUP. Les tampons d'entrée et de sortie pour IOCTL_REDIR_QUERY_PATH sont les suivants :

Paramètre disponible à l'adresse Format de la structure de données

Mémoire tampon d'entrée

IrpSp-> Parameters.DeviceIoControl.Type3InputBuffer

QUERY_PATH_REQUEST

Tampon de sortie

IRP->UserBuffer

QUERY_PATH_RESPONSE

L'IOCTL et les structures de données sont définies dans ntifs.h. Les tampons sont alloués à partir d'un pool non paginé.

Les redirecteurs de réseau ne doivent autoriser que les expéditeurs en mode noyau de cette IOCTL, en vérifiant que le membre RequesterMode de la structure IRP est KernelMode.

Le MUP utilise la structure de données QUERY_PATH_REQUEST pour les informations relatives à la requête.

typedef struct _QUERY_PATH_REQUEST {
    ULONG                PathNameLength;
    PIO_SECURITY_CONTEXT SecurityContext;
    WCHAR                FilePathName[1];
} QUERY_PATH_REQUEST, *PQUERY_PATH_REQUEST;
Membre de la structure Description

PathNameLength

Longueur, en octets, de la chaîne Unicode contenue dans le membre FilePathName.

SecurityContext

Un pointeur sur le contexte de sécurité.

FilePathName

Une chaîne Unicode terminée par un caractère non NULL de la forme <server><share><path>. La longueur de la chaîne, en octets, est spécifiée par le membre PathNameLength.

Les fournisseurs UNC doivent utiliser la structure de données QUERY_PATH_RESPONSE pour les informations de réponse.

typedef struct _QUERY_PATH_RESPONSE {
    ULONG  LengthAccepted;
} QUERY_PATH_RESPONSE, *PQUERY_PATH_RESPONSE;
Membre de la structure Description

LengthAccepted

Longueur, en octets, du préfixe réclamé par le fournisseur à partir de la chaîne de caractères Unicode spécifiée dans l'élément FilePathName de la structure QUERY_PATH_REQUEST.

Notez que IOCTL_REDIR_QUERY_PATH est une IOCTL de type METHOD_NEITHER. Cela signifie que les tampons d'entrée et de sortie peuvent ne pas être à la même adresse. Une erreur fréquente des fournisseurs de CNU est de supposer que les tampons d'entrée et de sortie sont identiques et d'utiliser le pointeur du tampon d'entrée pour fournir la réponse.

Lorsqu'un fournisseur UNC reçoit une requête IOCTL_REDIR_QUERY_PATH, il doit déterminer s'il peut traiter le chemin UNC spécifié dans l'élément FilePathName de la structure QUERY_PATH_REQUEST. Si c'est le cas, il doit mettre à jour le membre LengthAccepted de la structure QUERY_PATH_RESPONSE avec la longueur, en octets, du préfixe qu'il a réclamé, et terminer l'IRP avec STATUS_SUCCESS. Si le fournisseur ne peut pas traiter le chemin UNC spécifié, il doit rejeter la requête IOCTL_REDIR_QUERY_PATH avec un code d'erreur NTSTATUS approprié et ne doit pas mettre à jour l'élément LengthAccepted de la structure QUERY_PATH_RESPONSE. Les fournisseurs ne doivent en aucun cas modifier les autres membres ou la chaîne FilePathName.

Si le nom du préfixe \\Nserver\Nshare n'est pas reconnu en réponse à une IRP_MJ_CREATE ou à d'autres IRP utilisant des noms UNC, le code NTSTATUS recommandé à renvoyer est l'un des suivants :

STATUS_BAD_NETWORK_PATH
Le chemin d'accès au réseau est introuvable. Le nom de la machine (\\Nserver, par exemple) n'est pas valide ou le redirecteur réseau ne peut pas résoudre le nom de la machine (en utilisant les mécanismes de résolution de noms disponibles).

STATUS_BAD_NETWORK_NAME
Le nom de partage spécifié est introuvable sur le serveur distant. Le nom de la machine (Serveur, par exemple) est valide, mais le nom de partage spécifié est introuvable sur le serveur distant.

STATUS_INSUFFICIENT_RESOURCES
Les ressources disponibles étaient insuffisantes pour allouer de la mémoire aux tampons.

STATUS_INVALID_DEVICE_REQUEST
Une requête IOCTL_REDIR_QUERY_PATH ne doit provenir que du MUP et le mode demandeur de l'IRP doit toujours être KernelMode. Ce code d'erreur est renvoyé si le mode de requête du threading appelant n'était pas KernelMode.

STATUS_INVALID_PARAMETER
Le membre PathNameLength de la structure QUERY_PATH_REQUEST dépasse la longueur maximale autorisée, UNICODE_STRING_MAX_BYTES, pour une chaîne Unicode.

STATUS_LOGON_FAILURE ou STATUS_ACCESS_DENIED
Si l'opération de résolution du préfixe a échoué en raison d'informations d'identification invalides ou incorrectes, le fournisseur doit renvoyer le code d'erreur exact renvoyé par le serveur distant; ces codes d'erreur ne doivent pas être traduits en STATUS_BAD_NETWORK_NAME ou STATUS_BAD_NETWORK_PATH. Les codes d'erreur tels que STATUS_LOGON_FAILURE et STATUS_ACCESS_DENIED servent de mécanisme de commentaires à l'utilisateur, lui indiquant qu'il doit utiliser les informations d'identification appropriées. Ces codes d'erreur sont également utilisés dans certains cas pour demander automatiquement à l'utilisateur de fournir des informations d'identification. Sans ces codes d'erreur, l'utilisateur pourrait supposer que la machine n'est pas accessible.

Si le redirecteur de réseau n'est pas en mesure de résoudre un préfixe, il doit renvoyer un code NTSTATUS correspondant étroitement à la sémantique prévue dans la liste ci-dessus des codes NTSTATUS recommandés. Un redirecteur de réseau ne doit pas renvoyer l'erreur effectivement rencontrée (STATUS_CONNECTION_REFUSED, par exemple) directement au MUP si le code NTSTATUS ne figure pas dans la liste ci-dessus.

La longueur du préfixe revendiqué par le fournisseur dépend de chaque fournisseur UNC. La plupart des fournisseurs revendiquent généralement la partie \\<servername>\<sharename > d'un chemin de la forme \\<servername>\<sharename>\<path>. Par exemple, si un fournisseur a revendiqué \server\public avec un chemin d'accès \server\public\dir1\dir2, toutes les opérations basées sur le nom pour le préfixe \server\public (\server\public\file1, par exemple) seront automatiquement acheminées vers ce fournisseur sans aucune résolution de préfixe puisque le préfixe est déjà dans le cache des préfixes. Cependant, un chemin avec le préfixe \server\marketing\presentation passera par la résolution de préfixe.

Si un redirecteur de réseau revendique un nom de serveur (\\Nserver, par exemple), toutes les requêtes de partages sur ce serveur iront à ce redirecteur de réseau. Ce comportement est uniquement acceptable s'il n'est pas possible qu'un autre partage sur le même serveur soit accessible par un redirecteur réseau différent. Par exemple, un redirecteur réseau revendiquant « serveur » d'un chemin UNC empêchera l'accès d'autres redirecteurs réseau à d'autres partages sur ce serveur (accès WebDAV à « serveur », par exemple).

Tout redirecteur de réseau hérité (non basé sur l'utilisation de RDBSS) qui s'enregistre en tant que fournisseur d'UNC auprès de MUP en appelant FsRtlRegisterUncProvider recevra la requête IOCTL_REDIR_QUERY_PATH.

Un mini-redirecteur de réseau qui indique qu'il est pris en charge en tant que fournisseur de CNU recevra cette demande de préfixe comme s'il s'agissait d'un appel IRP_MJ_CREATE. Cette requête de création est similaire à un appel CreateFile en mode utilisateur avec l'indicateur FILE_CREATE_TREE_CONNECTION activé. Un mini-redirecteur de réseau ne recevra pas la demande de préfixe en tant qu'appel à MRxLowIOSubmit[LOWIO_OP_IOCTL]. Pour une revendication de préfixe, RDBSS enverra une requête MRxCreateSrvCall au mini-redirecteur de réseau, suivie d'un appel à MRxSrvCallWinnerNotify et à MRxCreateVNetRoot. Lorsqu'un mini-redirecteur de réseau s'enregistre auprès de RDBSS, la table de répartition du pilote pour le mini-redirecteur de réseau est copiée par RDBSS pour pointer vers les points d'entrée internes de RDBSS. Le RDBSS reçoit alors cet IOCTL_REDIR_QUERY_PATH en interne pour le mini-redirecteur de réseau et appelle MRxCreateSrvCall, MRxSrvCallWinnerNotify et MRxCreateVNetRoot. L'IRP IOCTL_REDIR_QUERY_PATH d'origine sera contenue dans la structure RX_CONTEXT transmise à la routine MRxCreateSrvCall. De plus, les membres suivants de la structure RX_CONTEXT transmise à la routine MRxCreateSrvCall sont modifiés :

Le membre MajorFunction est défini sur IRP_MJ_CREATE même si l'IRP d'origine était IRP_MJ_DEVICE_CONTROL.

Le membre PrefixClaim.SuppliedPathName.Buffer est défini sur le membre FilePathName de la structure QUERY_PATH_REQUEST.

Le membre PrefixClaim.SuppliedPathName.Length est défini sur le membre PathNameLength de la structure QUERY_PATH_REQUEST.

Le membre Create.NtCreateParameters.SecurityContext a pour valeur le membre SecurityContext de la structure QUERY_PATH_REQUEST.

Le membre Create.ThisIsATreeConnectOpen est défini sur TRUE.

Le bit RX_CONTEXT_CREATE_FLAG_UNC_NAME est défini dans le membre Create.Flags.

Si le mini-redirecteur de réseau veut voir les détails de la revendication de préfixe, il peut lire ces membres dans le RX_CONTEXT transmis à MRxCreateSrvCall. Sinon, il peut simplement tenter de se connecter au partage de serveur et renvoyer STATUS_SUCCESS si l'appel MRxCreateSrvCall a réussi. Le RDBSS fera la demande de préfixe au nom du mini-redirecteur de réseau.

Il existe un cas où un mini-redirecteur de réseau pourrait recevoir cet IOCTL directement. Un mini-répartiteur de réseau peut enregistrer une copie de sa table de répartition des pilotes avant de s'initialiser et de s'enregistrer auprès du RDBSS. Après avoir appelé RxRegisterMinirdr pour s'enregistrer auprès du RDBSS, le mini-répartiteur de réseau peut enregistrer une copie des nouveaux points d'entrée de la table de répartition des pilotes installés par le RDBSS et restaurer sa table de répartition des pilotes d'origine. Le tableau de répartition des pilotes restauré devrait être modifié de manière à ce qu'après avoir vérifié que les IRP reçues ne présentent pas d'intérêt pour le mini-répartiteur du réseau, l'appel soit transféré aux points d'entrée de répartition des pilotes de RDBSS. Le RDBSS copiera la table de répartition du pilote d'un mini-redirecteur de réseau lorsque le pilote initialisera le RDBSS et appellera RxRegisterMinrd Un mini-redirecteur de réseau qui établit un lien avec rdbsslib.lib doit sauvegarder sa table de répartition des pilotes originale avant d'appeler RxDriverEntry à partir de sa routine DriverEntry pour initialiser la bibliothèque statique RDBSS et restaurer sa table de répartition des pilotes après avoir appelé RxRegisterMinrdr. En effet, RDBSS copie la table de répartition des mini-redirecteurs de réseau dans les routines RxDriverEntry et RxRegisterMinrdr.

L'ordre dans lequel les fournisseurs sont interrogés lors de la résolution des préfixes est contrôlé par la valeur de registre REG_SZ ProviderOrder stockée sous la clé suivante :

HKLM\System\CurrentControlSet\Control\NetworkProvider\Order

Les noms de fournisseurs individuels dans la valeur de registre ProviderOrder sont séparés par des virgules, sans espace blanc en tête ou à la fin.

Par exemple, cette valeur pourrait contenir la chaîne :

RDPNP,LanmanWorkstation,WebClient

Étant donné un chemin UNC \\<server>\<share>\<path>, MUP émet une requête de résolution de préfixe si le préfixe (\server\share ou \server, par exemple) n'est pas trouvé dans le cache de préfixes de MUP. Le MUP envoie une requête de résolution de préfixe à chaque fournisseur dans l'ordre suivant jusqu'à ce qu'un fournisseur réclame le préfixe (ou que tous les fournisseurs aient été interrogés) :

  1. Client TS (RDPNP)

  2. Redirecteur SMB (LanmanWorkstation)

  3. Redirecteur WebDAV (WebClient)

Les modifications de la valeur du registre ProviderOrder nécessitent un redémarrage pour prendre effet dans MUP sur Windows Server 2003, Windows XP et Windows 2000.

MUP utilise chaque nom de fournisseur répertorié pour trouver la clé de registre du fournisseur sous la clé de registre suivante :

HKLM\System\CurrentControlSet\Services\<ProviderName>

MUP lit ensuite la valeur DeviceName sous la sous-clé NetworkProvider pour trouver le nom de l'appareil avec lequel le fournisseur s'enregistrera. Lorsque le fournisseur s'enregistre effectivement, MUP compare le nom de l'appareil transmis à la liste des noms d'appareils des fournisseurs connus et place le fournisseur dans une liste ordonnée aux fins de la résolution des préfixes. L'ordre des fournisseurs dans cette liste est basé sur l'ordre spécifié dans la valeur de registre ProviderOrder mentionnée ci-dessus.

Notez que cet ordre des fournisseurs est également respecté par le Multiple Provider Router (MPR), la DLL en mode utilisateur qui établit des connexions réseau sur la base de requêtes adressées aux fournisseurs WNet.

Avant Windows Server 2003 avec Service Pack 1 et Windows XP avec Service Pack 2, le comportement du MUP consistait à émettre des requêtes de résolution de préfixe à tous les fournisseurs « en parallèle » dans l'ordre spécifié dans la valeur de registre ProviderOrder, puis à attendre que tous les fournisseurs aient terminé l'opération de résolution de préfixe. Ainsi, même si le premier fournisseur a réclamé le préfixe, le MUP attend toujours que tous les autres fournisseurs aient terminé l'opération de résolution de préfixe. Lorsque plusieurs fournisseurs répondent à une demande de préfixe, MUP sélectionne le fournisseur en fonction de l'ordre spécifié dans la valeur de registre ProviderOrder.

Sous Windows XP Service Pack 2 et versions ultérieures et sous Windows Server 2003 Service Pack 1 et versions ultérieures, ce comportement a été légèrement modifié. MUP émet la requête de résolution de préfixe en série et s'arrête dès que le premier fournisseur réclame le préfixe. Ainsi, dans l'exemple ci-dessus, si RDPNP revendique un préfixe, MUP n'appellera pas les redirecteurs SMB ou WebDAV.

La principale raison pour laquelle ce comportement a été modifié est qu'un schéma de « résolution de préfixe en série » empêche les cas où un redirecteur réseau ayant une priorité inférieure dans la valeur ProviderOrder provoque des problèmes de performance pour un redirecteur réseau ayant une priorité supérieure dans la valeur ProviderOrder. Prenons l'exemple d'un serveur distant doté d'un pare-feu configuré pour bloquer certains types de paquets TCP/IP (accès à HTTP, par exemple), mais pour en autoriser d'autres (accès à SMB, par exemple). Dans ce cas, même si le redirecteur réseau SMB est configuré comme le premier fournisseur dans la valeur ProviderOrder et réclame le préfixe rapidement, le redirecteur WebDAV peut retarder considérablement la résolution du préfixe en attendant que la connexion TCP se termine