Création d'un utilitaire Linux: meilleure pratique pour les utilisateurs / groupes / autorisations


1

Je crée un utilitaire qui fonctionnera sur des machines Linux. Aux fins de cette discussion, disons qu'il est analogue de le faire.

Voici le problème: parfois, lorsque vous exécutez l'utilitaire, il crée des fichiers dans le répertoire dans lequel vous vous trouvez, et ceux-ci doivent être créés avec le même utilisateur / le même groupe que l'utilisateur qui exécute l'outil. Voici le scénario "make main.o" - créez main.o à partir de main.c. Ce sera la valeur par défaut lorsque vous exécuterez l'utilitaire en tant que votre propre utilisateur, ce qui est bien.

Parfois, lorsque vous exécutez l'utilitaire, il crée des fichiers dans / usr / local / bin et autres, qui doivent être root: root. C’est le scénario «sudo make install» - créez / usr / local / bin / executable sous root: root. Ce sera la valeur par défaut lorsque vous exécuterez l’utilitaire en tant que root, ce qui est bien.

Le problème est que, dans tous les cas, l'utilitaire doit gérer des fichiers de cache supplémentaires, par exemple dans / var / cache / utility. Lorsque vous exécutez l'utilitaire en tant que root, ces fichiers sont root: root, ce qui pose un problème lors de la prochaine exécution de l'utilitaire en tant qu'utilisateur normal. Ils ne peuvent pas être supprimés / modifiés.

Ce que je me demande, est-ce une bonne idée de créer un utilisateur / groupe dédié pour cet utilitaire lorsque vous l'installez? Je sais apache, svn, et d'autres le font. C’est la seule approche à laquelle je puisse penser, mais je suis ouvert à d’autres solutions.

Si j’ai un utilisateur / groupe dédié à l’utilitaire, comment puis-je assumer temporairement l’identité de cet utilisateur aux fins de la gestion des fichiers de cache, puis reprendre l’identité précédente pour le reste de l’exécution (pour créer des fichiers normaux en tant qu’utilisateur)? : utilisateur et fichiers système en tant que root: root)?

Ce que j'ai jusqu'à présent ressemble à ceci:

  • getpwnam (predefined_utility_user_name) // récupère l'ID utilisateur
  • seteuid (utility_uid)
  • setegid (utility_gid)

// faire des choses dans / var / cache / utility

  • seteuid (getuid ()) // reprend l'identifiant précédent
  • setegid (getgid ()) // reprend le groupe précédent

LE PROBLÈME: en supposant que predefined_identity ne fonctionne PAS lorsque vous exécutez l'utilitaire en tant que vous-même! Cela fonctionne lorsque vous exécutez en tant que root (évidemment).

Je vais bien en ajoutant moi-même et d'autres utilisateurs au groupe associé à l'utilitaire. Cependant, cela ne fonctionne pas. Alors, comment puis-je faire ce travail? Est-ce une mauvaise idée?

EDIT: Réponse à la suggestion ci-dessous

J'ai lu un peu plus et je pense avoir une bonne solution en utilisant le n ° 2 que vous avez suggéré:

L'exécutable de l'utilitaire appartient à utility: utility et possède les autorisations u + s et g + s. Par conséquent, dès que je commence à exécuter, j'ai euid / egid d'utilitaire et utilitaire, respectivement. J'ai ruid / rgid de l'utilisateur qui a exécuté le programme. Donc, ce que je peux faire, c'est quand je commence à exécuter, setegid (getgid ()) et seteuid (getuid ()). Cela permet au processus d'assumer l'identité de celui qui a exécuté le programme. Je maintiendrai cela pendant toute la durée du programme, SAUF en traitant avec / var / cache / utility, j'utilise la même technique pour assumer l'utilitaire: identité d'utilitaire.

Je n'ai pas besoin de partitionner le logiciel, il n'y a pas de groupe auquel votre utilisateur doit appartenir, l'exécutable a juste besoin de son propre utilisateur / groupe et de u + s et g + s. Je suppose que vous devez être convaincu que le programme n'est pas malveillant, mais vous devez le supposer de toute façon si vous voulez l'exécuter. Pensées?


Salut Todd. Cela semble être une bonne solution. Je pense que la sécurité n'est pas un problème, car quand un utilisateur appelle l'utilitaire, il reçoit tous ses accès.
Kevin A. Naudé

Réponses:


0

Par souci de clarté, le problème de votre code est que les utilisateurs non privilégiés ne peuvent définir l’identificateur de domaine que dans quelques cas, en fonction de la manière dont l’exécutable a été appelé. Nous avons donc besoin d'une autre solution.

C'est un problème intéressant. Vous pouvez le résoudre de différentes manières. Je ne sais pas s'il existe une solution de meilleure pratique acceptée, mais voici quelques options.

  1. Définissez les autorisations du groupe collant sur /var/cache/utility.

    Cette approche permet à votre utilitaire de s'exécuter sous les autorisations d'initiateurs. Assurez-vous que l'utilisateur est dans le groupe qui appartient /var/cache/utilityet modifiez les autorisations afin que l'attribution de groupe reste collante pour tous les contenus. Vous pouvez accomplir cela avec ce qui suit:

    mkdir /var/cache/utility
    chown -R :user /var/cache/utility
    chmod 2770 /var/cache/utility
    usermod -a -G users joe
    

    Maintenant, depuis joeest dans le users, quand il lance votre utilitaire, tout va bien. La premission de groupe de tous les fichiers modifiés /var/cache/utilityrestera users. Le problème est qu’il n’existe aucun groupe auquel tous les utilisateurs appartiennent automatiquement. Donc, cette méthode ne fonctionnera pas automatiquement pour tous les utilisateurs. Il y a aussi le problème de sécurité. Votre utilitaire peut modifier les fichiers de /var/cache/utilitymanière appropriée, mais cette méthode ouvre les portes de l'inondation à l'ouest sauvage du pays de l'utilisateur.

  2. Divisez votre utilitaire en deux parties.

    Diviser l'utilitaire en deux parties constitue un inconvénient, mais vous oblige à formaliser l'interface opérationnelle. La communication entre les parties peut prendre deux formes communes:

    • Communications Socket, qu’il s’agisse de sockets unix ou TCP. Cela nécessite que votre back-end soit un service.

    • Outils de ligne de commande. C’est beaucoup plus simple que d’utiliser des sockets et votre back-end ne fonctionne pas continuellement.

    L'idée est de uid-execute-sticky-bit sur votre back-end, afin qu'il s'exécute automatiquement sous le compte du propriétaire, quel que soit l'utilisateur actuellement connecté. Le serveur frontal sera toujours exécuté sous les informations d'identification de l'utilisateur.

    Voyez si vous pouvez fractionner votre utilitaire afin que toutes les manipulations du cache soient effectuées par le serveur principal, mais que d'autres activités soient effectuées dans le serveur frontal. Vous pouvez définir le uid du back-end comme suit:

    chmod u+s /usr/bin/utility-back-end
    

    Il y a un assez bon aperçu de cette technique ici . Il est toujours un peu gênant de partitionner le logiciel de cette manière, mais c’est la meilleure solution que je connaisse. La commande suivante répertorie tous les utilitaires de votre système qui utilisent déjà cette méthode:

    find / -xdev \( -perm -4000 \) -type f -print0 | xargs -0 ls -l
    

J'espère que ça t'as aidé.


/ etc / passwd est lisible par tout le monde (sinon, des outils tels que lsne pourraient pas mapper les valeurs numériques d'ID utilisateur / gid sur les noms d'utilisateur ou de groupe appropriés). / etc / shadow a une lisibilité limitée, car il contient les mots de passe chiffrés lorsque le système est exécuté avec des mots de passe shadow.
un CVn

@ MichaelKjörling Merci, Michael. J'ai corrigé le texte en conséquence. Le problème est principalement associé aux restrictions qui s'appliquent à seteuid et setegid.
Kevin A. Naudé

Merci beaucoup pour vos idées. Voir ci-dessus pour ma réponse .. trop long pour le champ commentaire.
Todd Freed
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.