Il peut arriver d'avoir besoin d'automatiser des actions sur un serveur linux via une page web, typiquement en PHP. Ne trouvant que peu de documentation sur ce principe, je vous propose une solution qui devrait fonctionner sur la majorité des serveurs (testée sous Debian et Ubuntu pour mon cas).
Nous allons dans cet exemple redémarrer le service DNS (Bind9) grâce à un formulaire html exécutant cette fameuse commande via un bout de code PHP.
Identifier l'utilisateur Apache
Les scripts PHP interprétés par Apache sont exécutés par un utilisateur système. Généralement il s'agit de "www-data", mais il peut varier selon les distributions et configurations. Pour récupérer ce nom d'utilisateur vous avez trois solutions :
- Ouvrir le fichier de configuration Apache "apache2.conf", généralement situé dans /etc/apache2/apache2.conf (si vous le ne trouvez pas faites un "locate apache2.conf" il devrait vous indiquer son emplacement). Dans le premier quart tu fichier vous devriez trouver l'information voulue :
- Ouvrir le fichier des utilisateurs systèmes /etc/group/ et cherchez celui qui semble correspondre
- Lancer le service Apache (en root : /etc/init.d/apache2 start) puis faites un : ps aux | grep apache2. Vous devriez avoir le nom d'utilisateur sous lequel le service fonctionne.
Le fichier sudoers
Nous allons utiliser la commande sudo qui va permettre à l'utilisateur Apache (www-data pour mon cas) de lancer une commande qui n'est habituellement exécutable qu'en root. Je vous conseilel de lire cette documentation si vous n'avez jamais entendu parlé de sudo.
Editez le fichier /etc/sudoers via la commande visudo (il est fortement déconseiller de l'éditer directement), puis trouvez cette ligne :
root ALL=(ALL) ALL
En dessous de cette ligne ajoutez :
www-data ALL=(ALL) NOPASSWD:/etc/init.d/bind9 restart
Pensez à remplacer www-data par votre utilisateur s'il diffère (cf. première étape).
Grâce à cette ligne nous autorisons l'utilisateur d'Apache a exécuter cette commande, et uniquement celle-ci ! C'est un point important sur la sécurité de votre système. Dans le cas contraire sachez que la sécurité de votre système serait totalement compromise :
www-data ALL=(ALL) NOPASSWD:ALL
Dans ce cas précis, vous autorisez toutes les commandes du systèmes à être exécutées par votre utilisateur Apache, bien évidemment c'est fortement déconseillé !
Le cas d'un script shell
Si vous préférez exécuter un script (.sh) qui s'occupera lui même de réaliser cette opération, il vous faut placer dans votre fichier /etc/sudoers (toujours via la commande visudo) le code suivant (ignorer dans ce cas la première manipulation) :
www-data ALL=(ALL) NOPASSWD: DNSRELOAD # Cmnd alias specification Cmnd_Alias DNSRELOAD = /chemin/vers/votre/script.sh
D'une façon générale :
Cmnd_Alias NomDeVotreAlias = NomDeVotreAlias ListeDeCommandesSepareesParDesVirgules
OU (dans le cas d'un script)
Cmnd_Alias NomDeVotreAlias = NomDeVotreAlias /chemin/vers/votre/script/
Le script s'exécutant "en tant que" root vous ne devriez pas avoir de souci de droits, dans le cas contraire :
#: chown www-data:www-data /chemin/vers/votre/script.sh
Vous pouvez également faire plus simple en sautant ces étapes pour directement placer le code suivant dans /etc/sudoers (mais les possibilités de "dérives" vers d'autres utilisations sont moins nombreuses) :
www-data ALL=(ALL) NOPASSWD: /chemin/vers/votre/script.sh
L'exécution du script PHP
Il vous suffira ensuite de lancer la commande grâce à la fonction exec de PHP. Dans le cas ou vous souhaitez relancer Bind sans script (.sh) :
<?PHP exec('sudo -u www-data /etc/init.d/bind9 restart'); exit; ?>
Dans le cas ou vous utilisez un script :
<?PHP exec('sudo -u www-data /chemin/vers/votre/script.sh'); exit; ?>
Pensez à remplacer www-data par votre utilisateur Apache s'il diffère 😉
Conclusion
Il ne vous reste plus faire un petit formulaire (x)html très simple avec un bouton "Redémarrer Bind" et le tour est joué ! Sachez que cette technique fonctionne même si vous avez Suhosin-patch d'installé.
Si toutefois cette solution ne vous convient pas, il vous reste la solution des scripts SUID, à condition dans ce cas d'avoir solides connaissances en matière de permissions sur les fichiers.
Auteur : Mr Xhark
Fondateur du blog et passionné par les nouvelles techno, suivez-moi sur twitter
14 commentaires
merci, cela m'éclaire. Je n'ai pu identifier l'user apache2 que via la solution no 3.
Mais le reste, tourné dans tous les sens ne marche pas...
j'ai passé plusieurs jours dessus ré exécutant ces mêmes actions: rien
seul www-data ALL=(ALL) NOPASSWD:ALL marche mais n'est pas sécurisé DU TOUT
Après tant de temps passé sur le sujet (si on met tout bout à bout ça fait bien une semaine) pour ma part j'ai enfin réussi...
Mon script à enfin marché quand j'ai enlevé "-u www-data" dans l'exécution du php
ce qui donne
exec("sudo /chemin_vers_le_script/monscript.sh");
mais je luis préfère
passthru ("sudo /chemin_vers_le_script/monscript.sh",$error);
qui me renvoie si il a une erreur
Seul mon script est exécuté et seulement lui
Une solution sale, et si peu sécurisée...
LA bonne méthode, c'est le wrapper :
http://blog.khemael.net/2010/08/26/de-la-maniere-de-faire-de-lexec-et-system-root-en-php/3/
@Tchai : je ne connaissais pas cette méthode des wrappers, merci pour l'info !
Avec ce tuto, est-ce qu'on peut faire de la programmation système avec PHP qui va lancer des applications root comme /etc/init.d/postgresql start?
Merci
@TTinvent: tout à fait
Merci beaucoup pour ce tuto, je vais de ce pas jeter un œil sur le reste du site
j'ai installé un serveur XAMPP, donc dans mon cas comment connaitre l'utilisateur qui exécute ce script
@kamal: Tout est dans /xx/lampp/etc/httpd.conf
De mon coté je n'y arrive vraiment pas...
j'ai essayer avec NOPASSWD: ALL, et ça ne marche tout de même pas sous Ubuntu
Bonjour
J'ai longtemps été confronté à ce problème:
Voici ce que j'ai comme solution:
il est possible de donnée des droits à un fichier de cette manière
sudo chmod u+s which 'commande'
s : Sticky Bit
@jolinar008: oui tu peux aussi utiliser le sticky bit mais il faut rester prudent car moins "visible"
@Mr Xhark: Ne pas tout mélanger, on parle de suid, sgid et sticky bit qui a un autre sens que les deux précédents. Maintenant pour le suid root sur des scripts shell, cela fait x années que cela n'est pas pris en compte par le shell bash sous diverses distributions Linux. Suid et Sgid ne fonctionnent que pour des binaires (et heureusement) ...
Merci. explication complète.
Au passage j'ai remarqué que la fonction marche sans "-u www-data" dans la commande. Et pas avec.