Le code suivant génère une erreur s'il est exécuté par un utilisateur non root pour un fichier appartenant à root, même lorsque l'utilisateur non root dispose des privilèges Sudo:
try:
f = open(filename, "w+")
except IOError:
sys.stderr.write('Error: Failed to open file %s' % (filename))
f.write(response + "\n" + new_line)
f.close()
Existe-t-il un moyen d'exécuter open(filename, "w+")
avec les privilèges Sudo, ou une fonction alternative qui fait cela?
Vous avez quelques options:
os.geteuid() != 0
), puis appelez-vous avec Sudo
infront (qui demandera à l'utilisateur d'entrer son mot de passe) et quittez:
import os
import sys
import subprocess
if os.geteuid() == 0:
print("We're root!")
else:
print("We're not root.")
subprocess.call(['Sudo', 'python3', *sys.argv])
sys.exit()
L'appeler ressemble à ceci:
$ python3 be_root.py
We're not root.
Password:
We're root!
réponse de L3viathan a un SynaxError Edit: fonctionne très bien sur Python 3.5+. Voici une version pour Python 3.4.3 (distribuée par défaut sur Ubuntu 16.04) et ci-dessous:
if os.geteuid() == 0:
# do root things
else:
subprocess.call(['Sudo', 'python3'] + sys.argv) # modified
Cependant, j'ai opté pour une approche différente car cela a simplifié le code qui l'entoure dans mon cas d'utilisation:
if os.geteuid() != 0:
os.execvp('Sudo', ['Sudo', 'python3'] + sys.argv)
# do root things
réponse de L3viathan dépend de PEP 448 , qui a été inclus dans Python 3.5 et a introduit des contextes supplémentaires où l'expansion des arguments en étoile est autorisée. Pour Python 3.4 et versions antérieures, la concaténation de liste peut être utilisée pour faire la même chose:
import os
import sys
import subprocess
if os.geteuid() == 0:
print("We're root!")
else:
print("We're not root.")
subprocess.call(['Sudo', 'python3'] + sys.argv) # modified
Mais note: subprocess.call()
lance un processus enfant, ce qui signifie qu'après que root aura fini d'exécuter le script, l'utilisateur d'origine continuera d'exécuter son script en tant que bien. Cela signifie que vous devez placer la logique élevée dans un côté d'un bloc if/else
Afin que lorsque le script d'origine se termine, il n'essaie pas d'exécuter la logique qui nécessite une élévation (l'exemple de L3viathan fait cela).
Ce n'est pas nécessairement une mauvaise chose - cela signifie que la logique normale/élevée peut être écrite dans le même script et bien séparée - mais ma tâche nécessite une racine pour toute la logique. Je ne voulais pas perdre un niveau d'indentation si l'autre bloc devait être vide, et je n'avais pas réalisé comment l'utilisation d'un processus enfant affecterait les choses, alors j'ai essayé ceci:
import os
import sys
import subprocess
if os.geteuid() != 0:
subprocess.call(['Sudo', 'python3'] + sys.argv)
# do things that require root
... et il s'est cassé bien sûr, car après que root a été fait, l'utilisateur régulier a repris l'exécution de son script et a essayé d'exécuter les instructions qui nécessitaient root.
Puis j'ai trouvé cet Gist recommandant os.execvp()
- qui remplace le processus en cours au lieu de lancer un enfant:
import os
import sys
if os.geteuid() != 0:
os.execvp('Sudo', ['Sudo', 'python3'] + sys.argv) # final version
# do things that require root
Cela semble se comporter comme prévu, enregistre un niveau d'indentation et 3 lignes de code.
Avertissement: je ne connaissais pas os.execvp()
il y a dix minutes, et je ne sais encore rien sur les pièges ou subtilités possibles autour de son utilisation. YMMV.
Votre script est limité aux autorisations avec lesquelles il est exécuté car vous ne pouvez pas modifier les utilisateurs sans avoir déjà les privilèges root.
Comme l'a dit Rob, la seule façon de le faire sans modifier vos autorisations de fichier est d'exécuter avec Sudo
.
Sudo python ./your_file.py
Avoir la possibilité d'utiliser Sudo
ne vous donne aucun privilège si vous ne l'utilisez pas réellement. Donc, comme d'autres l'ont suggéré, vous devriez probablement démarrer votre programme en utilisant Sudo
. Mais si vous n'aimez pas cette idée (je ne vois aucune raison à cela), vous pouvez faire un autre tour.
Votre script peut vérifier s'il est exécuté avec des privilèges root ou s'il fonctionne uniquement avec des privilèges utilisateur. Le script peut réellement s'exécuter avec des privilèges plus élevés. Voici un exemple (veuillez noter que le stockage du mot de passe dans le code source n'est pas une bonne idée).
import os.path
import subprocess
password_for_Sudo = 'pass'
def started_as_root():
if subprocess.check_output('whoami').strip() == 'root':
return True
return False
def runing_with_root_privileges():
print 'I have the power!'
def main():
if started_as_root():
print 'OK, I have root privileges. Calling the function...'
runing_with_root_privileges()
else:
print "I'm just a user. Need to start new process with root privileges..."
current_script = os.path.realpath(__file__)
os.system('echo %s|Sudo -S python %s' % (password_for_Sudo, current_script))
if __name__ == '__main__':
main()
Production:
$ python test.py
I'm just a user. Need to start new process with root privileges...
OK, I have root privileges. Calling the function...
I have the power!
$ Sudo python test.py
OK, I have root privileges.
Calling the function...
I have the power!
J'aime la réponse de L3viathan. J'ajouterais une quatrième option: utilisez subprocess.Popen () pour exécuter une commande sh pour écrire le fichier. Quelque chose comme subprocess.Popen('Sudo echo \'{}\' > {}'.format(new_line, filename))
.