7
votes

Comment déterminer si un chemin est à l'intérieur d'un répertoire? (POSIX)

in c, à l'aide d'appels POSIX, comment puis-je déterminer si un chemin est à l'intérieur d'un répertoire cible?

Par exemple, un serveur Web a son répertoire racine dans / srv , ceci est getcwd () pour le démon. Lors de l'analyse d'une demande de /index.html , il renvoie le contenu de /sr/index.html .

Comment puis-je filtrer les demandes de cheminements en dehors de / srv ?

/../c / passwd , / valide /../../ etc / passwd , c.

fractionnement du chemin à / et rejeter tout tableau contenant .. va casser des accès valides / srv / valide /../ index.html .

Y a-t-il une façon canonique de le faire avec des appels système? Ou dois-je marcher manuellement sur le chemin et la profondeur du répertoire compter?


2 commentaires

Je pense que c'est la raison chroot (2) a été inventé!


@Carl Norum: Chroot est meilleur si vous donnez un accès à une coque limitée. Si vous souhaitez limiter l'accès à un programme que vous créez, il existe de meilleures options que Chroot.


3 Réponses :


6
votes

Il y a toujours realpath :

La fonction realpath () doit dériver, à partir du chemin de chemin pointé sur * nom_fichier *, un chemin de chemin absolu qui résout à la même entrée de répertoire, dont la résolution n'implique pas "". , '..' ou liens symboliques.

Comparez ensuite ce que realpath vous donne avec votre répertoire racine souhaité et voyez s'ils correspondent.

Vous pouvez également nettoyer le nom de fichier à la main en développant les doubles points avant de préparer le "/ srv" . Divisez le chemin entrant sur des barres obliques et passez à travers la pièce par pièce. Si vous obtenez un "." puis retirez-le et passez à autre chose; Si vous obtenez un ".." , supprimez-le et le composant précédent (en prenant soin de ne pas dépasser la première entrée de votre liste); Si vous obtenez autre chose, passez juste sur le composant suivant. Puis coller ce qui reste de retour avec des barres obliques entre les composants et prépendez votre "/ srv /" . Donc, si une personne vous donne "/ valide /../../ etc / passwd" , vous vous retrouverez avec "/ srv / etc / passwd" et < Code> "/ où / est /../ crêpes / maison" finira par "/ srv / where / pancakes / house" . .

De cette façon, vous ne pouvez pas obtenir l'extérieur "/ srv" (sauf par des liens symboliques bien sûr) et un entrant "/../." sera le même que "/" (comme dans un système de fichiers normal). Mais vous voudrez toujours utiliser realpath si vous êtes inquiet de symbolique sous "/ srv" .

Utiliser avec la composante Nom du chemin par composant vous permettrait également de casser la connexion entre la mise en page que vous présentez au monde extérieur et la mise en page réelle du système de fichiers; Il n'y a pas besoin de "/ ceci / that / the / the / chose" pour mapper sur un "/ srv / this / that / the / the / chose" n'importe où, le chemin pourrait simplement être une clé dans une sorte de base de données ou une sorte de chemin d'espace de noms à un appel de fonction.


0 commentaires

0
votes

Vous devez simplement traiter .. vous-même et supprimer le composant de chemin précédent lorsqu'il est trouvé, de sorte qu'il n'y ait aucune occurrence de .. dans la chaîne finale que vous utilisez pour Ouverture de fichiers.


0 commentaires

2
votes

Pour déterminer si un fichier F est dans un répertoire D, première statistique D pour déterminer son numéro de périphérique et son numéro d'inode (Membres ST_Dev et ST_INO de Struct STAT).

STATS F Pour déterminer s'il s'agit d'un répertoire. Sinon, appelez BASNEname pour déterminer le nom du répertoire le contenant. Définissez g sur le nom de ce répertoire. Si f était déjà un répertoire, définissez g = f. P>

maintenant, f est dans D Si et seulement si g est dans D. Ensuite, nous avons une boucle. P>

int samefile(dev_t ddev, ino_t dino, const char *path) {
  struct stat st;
  if (0 == stat(path, &st)) {
    return ddev == st.st_dev && dino == st.st_no;
  } else {
    throw ...; // or return error value (but also change the caller to detect it)
  }
}


0 commentaires