Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

Lancer une fonction python avec sudo

+6 votes

Mon programme ne nécessite pas les droits root à l'exception d'une fonction qui écrit dans un fichier uniquement accessible en écriture par root.
Est-ce que je peux lancer uniquement cette fonction avec les droits root, autrement qu'en l'écrivant dans un fichier séparé que j'exécuterai avec un subprocess.call(["sudo", "mafonction.py"]) ?

demandé 10-Jul-2015 par Laërte (346 points)

pas très bien compris ce que tu essayes de faire et surtout pourquoi tu ne veux pas utiliser subprocess, et encore moins pourquoi tu parles de fichier séparé =/

Si je veux lancer une seule fonction en tant qu'administrateur, la solution la plus simple est de l'écrire dans un fichier et d'exécuter ce fichier avec subprocess. Mais est-ce qu'il y a une solution plus élégante pour exécuter cette fonction en tant que root ?

Pour donner un exemple peut-être plus parlant : la totalité ou presque de mon programme consiste en une interface graphique qui se contente de récupérer les infos que veut bien me donner l'utilisateur, pour ensuite les écrire dans un fichier lorsqu'il appuie sur un bouton. Ce fichier n'est accessible en écriture qu'à root. Il faudrait donc faire la demande de mot de passe uniquement à ce moment-là. Comme le fait Apper (gestionnaire de paquet deb sous KDE), qui ne demande le mot de passe que lors de l'installation des paquets et pas lors de la recherche.

Concrètement c'est une question qui a été posée ici et à laquelle personne n'a vraiment trouvé de réponse satisfaisante...

Tu peux lancer ton programme en root, puis forker : un fork drop ses droits (avec setuid et setgid), l'autre les conserve mais ne fait que s'occuper de ta fonction qui a besoin des droits.

Si tu veux que n'importe quel user puisse lancer ton programme, tu lui mettre le bit setuid.

2 Réponses

0 votes

OPTION 0 : DU TRUC QUE TU NE VEUX PAS FAIRE

en gros tu ne veux pas faire un truc du genre ? :

import subprocess
returncode = subprocess.call(["/usr/bin/sudo", "/usr/bin/id"])

OPTION 1 : JE RECUP LE MDP DU MEC EN CLAIR

Sinon au moment opportun tu récupères le mot de passe du mec pour ensuite l'utiliser pour ta commande nécéssitant les droits root (bof bof la sécurité pour le coup si le mdp est ensuite stockée en clair sans hachage dans un serveur accessible via internet) et tu fais un truc du genre :

sudoPassword = 'mypass' # On récup(en input) le mot de passe de l'user au moment opportun
command = 'mount -t vboxsf myfolder /home/myuser/myfolder'
p = os.system('echo %s|sudo -S %s' % (sudoPassword, command)) # ensuite on l'utilise

OPTION 2 : J'OUVRE UN TERMINAL POP UP EN PLEIN MILIEU DE L'APPLI

ça donne une solution du genre :

os.system("xterm -c \"sudo /home/checkit/fellowsbook\"")

OPTION 3 : JE LANCE MON SCRIPT AVEC GKSUDO

genre si le script c'est :

#!/usr/bin/env python
import os
os.system("/home/checkit/fellowsbook")

Je l'exécute avec :

gksu python_script.py

OPTION 4

Bon il est 4h + du matin dans le bled où je me trouve, bonne nuit all flemme, de réfléchir à l'option 4 ... ;)

répondu 11-Jul-2015 par boblinux (3,094 points)
edité 12-Jul-2015 par boblinux

Va falloir que tu m'explique pourquoi la sécurité est bof pour ta solution 1. Je vois pas où est le problème...

Sinon toutes tes solutions nécessite que la fonction qui nécessite les droits root soit écrite dans un fichier externe, or en l'occurence c'est une méthode de ma classe gaphique.

En fait, j'ai oublié de préciser que c'est un plan foireux que si tu stockes le mpd en clair sur un serveur :

Soyons clair: stocker en clair des informations confidentielles, comme
un mot de passe, sur un serveur accessible par Internet est une faute
professionnelle, qui peut avoir des conséquences importantes, y
compris légales.

Le mot de passe n'est pas stocké, puisqu'il provient d'une fonction input (ou autre, j'utiliserai probablement une interface graphique pour récupérer le mot de passe)

Ou alors j'ai pas du tout compris ton exemple... ^^

On ne parle pas de la même chose, quand je dis que l'option n'est pas sécurisée, je parle uniquement dans un cadre où le programmeur stocke le mdp en clair sur une base de donnée, et apparemment ce n'est pas ton cas, donc pour toi il n'y a pas de souci avec cette méthode ;)

Dans un terminal, récupérer un password de manière sécurisée se fait : from getpass import getpass; getpass(). Il est aussi courant de passer le mot de pass à un script via une option de la ligne de commande (voir argparse) ou via une variable d'environnement (os.environ). Une fois le password acquis, l'option 1 me semble la plus sure.

+1 vote

A mon sens, le plus simple serais de :

  • lancer ton programme en tant que root (ou en lui donnant les droit suid)
  • forker un process (multiprocessing.Process) qui gardera les droits root et dont le rôle sera d'écrire dans ton fichier
  • dans le process de base, dropper les droit roots et continuer l'exécution classique

Lorsque tu aura besoin d'écrire dans ton fichier, il suffit au process de base de communiquer avec ton process root qui le fera.
Pour le système de communication inter-process, multiprocessing dispose de quelques fonctions, sinon ZMQ peux t'aider.

C'est AFAIK globalement le fonctionnement de Postfix.

répondu 24-Mai-2016 par ivoire (198 points)
edité 24-Mai-2016 par ivoire
...