Erminig/erminig/core/security.py

70 lines
2 KiB
Python
Raw Permalink Normal View History

#
# Erminig - Fonctions pour gérer les utilisateurs système.
# Copyright (C) 2025 L0m1g
# Sous licence DOUARN - Voir le fichier LICENCE pour les détails
#
# Ce fichier fait partie du projet Erminig.
# Libre comme lair, stable comme un menhir, et salé comme le beurre.
#
2025-04-29 17:15:19 +02:00
import os
import pwd
import sys
import functools
def check_root():
"""Vérifie si on est root, sinon quitte."""
if os.geteuid() != 0:
print("[SECURITY] Ce programme doit être exécuté en tant que root.")
sys.exit(1)
def check_user_exists(username):
"""Vérifie si l'utilisateur spécifié existe."""
try:
pwd.getpwnam(username)
return True
except KeyError:
print(f"[SECURITY] Utilisateur '{username}' introuvable.")
return False
def run_as_user(username):
"""Décorateur : Fork et drop privileges pour exécuter une fonction sous un autre utilisateur."""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
try:
pid = os.fork()
if pid > 0:
2025-05-03 16:11:28 +02:00
# Parent : attendre le child, ne pas exit, juste return proprement
2025-04-29 17:15:19 +02:00
_, status = os.waitpid(pid, 0)
2025-05-03 16:19:45 +02:00
return (
status >> 8
) # récupère le code retour du fils (comme exit code)
2025-04-29 17:15:19 +02:00
# Child
pw_record = pwd.getpwnam(username)
user_uid = pw_record.pw_uid
user_gid = pw_record.pw_gid
os.setgid(user_gid)
os.setuid(user_uid)
os.environ["HOME"] = pw_record.pw_dir
os.environ["LOGNAME"] = pw_record.pw_name
os.environ["USER"] = pw_record.pw_name
2025-04-29 17:15:19 +02:00
result = func(*args, **kwargs)
2025-05-03 16:11:28 +02:00
os._exit(0 if result is None else int(bool(result)))
2025-04-29 17:15:19 +02:00
except OSError as e:
print(f"[SECURITY] Fork échoué : {e}")
2025-05-03 16:11:28 +02:00
os._exit(1)
2025-04-29 17:15:19 +02:00
return wrapper
2025-05-03 16:19:45 +02:00
return decorator