Ajoute les groupes de sécurité à l'audit GPResult machine
This commit is contained in:
1 parent
0fb81f2a9c
commit
b48c4c5412
1 file changed
+406
-47
@@ -1,9 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""Audit GPResult machine : resultat structure dans audit-gpresult.computer-gpo.
|
|
||||||
|
|
||||||
L'installation est vide. La collecte, l'analyse XML et l'enregistrement
|
|
||||||
des donnees sont realises uniquement lors de l'execution de audit().
|
|
||||||
"""
|
|
||||||
|
|
||||||
from setuphelpers import *
|
from setuphelpers import *
|
||||||
|
|
||||||
@@ -12,32 +7,63 @@ import tempfile
|
|||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
|
||||||
# Categorie et cle des donnees d'audit WAPT.
|
# ---------------------------------------------------------------------------
|
||||||
|
# Identifiants de l'audit WAPT
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
AUDIT_SECTION = "audit-gpresult"
|
AUDIT_SECTION = "audit-gpresult"
|
||||||
AUDIT_NAME = "computer-gpo"
|
AUDIT_NAME = "computer-gpo"
|
||||||
|
|
||||||
|
|
||||||
def install():
|
def install():
|
||||||
"""Point d'entree d'installation ; aucune configuration a appliquer."""
|
"""
|
||||||
|
Ce paquet est uniquement destiné à l'audit.
|
||||||
|
|
||||||
|
Aucune action d'installation n'est nécessaire sur le poste.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Fonctions utilitaires XML
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def _clean_tag(tag):
|
def _clean_tag(tag):
|
||||||
"""Retire l'espace de noms XML eventuel d'une balise."""
|
"""
|
||||||
|
Supprime le namespace XML d'un tag.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
"{http://www.microsoft.com/GroupPolicy/Rsop}Name"
|
||||||
|
devient :
|
||||||
|
"Name"
|
||||||
|
|
||||||
|
Les fichiers XML générés par GPResult utilisent des namespaces.
|
||||||
|
Les supprimer permet de rendre le parseur indépendant du namespace
|
||||||
|
utilisé par Windows.
|
||||||
|
"""
|
||||||
return tag.split("}")[-1]
|
return tag.split("}")[-1]
|
||||||
|
|
||||||
|
|
||||||
def _text(element, tag, default=""):
|
def _text(element, tag, default=""):
|
||||||
"""Lit le premier texte non vide d'une balise dans tout le sous-arbre.
|
"""
|
||||||
|
Retourne le contenu texte du premier élément XML correspondant.
|
||||||
|
|
||||||
La recherche est recursive et insensible a la casse. Si aucune valeur
|
La recherche est récursive et ignore les namespaces XML.
|
||||||
n'est trouvee, retourne la valeur par defaut.
|
|
||||||
|
Args:
|
||||||
|
element: élément XML à partir duquel effectuer la recherche.
|
||||||
|
tag: nom du tag recherché.
|
||||||
|
default: valeur retournée si le tag n'est pas trouvé.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str
|
||||||
"""
|
"""
|
||||||
if element is None:
|
if element is None:
|
||||||
return default
|
return default
|
||||||
|
|
||||||
for child in element.iter():
|
for child in element.iter():
|
||||||
if _clean_tag(child.tag).lower() == tag.lower():
|
if _clean_tag(child.tag).lower() == tag.lower():
|
||||||
|
|
||||||
if child.text:
|
if child.text:
|
||||||
return child.text.strip()
|
return child.text.strip()
|
||||||
|
|
||||||
@@ -45,7 +71,10 @@ def _text(element, tag, default=""):
|
|||||||
|
|
||||||
|
|
||||||
def _to_bool(value):
|
def _to_bool(value):
|
||||||
"""Convertit les valeurs reconnues en True ; toute autre valeur est False."""
|
"""
|
||||||
|
Convertit les représentations textuelles courantes d'un booléen
|
||||||
|
en booléen Python.
|
||||||
|
"""
|
||||||
return str(value).strip().lower() in (
|
return str(value).strip().lower() in (
|
||||||
"true",
|
"true",
|
||||||
"1",
|
"1",
|
||||||
@@ -54,37 +83,94 @@ def _to_bool(value):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _split_account(account):
|
||||||
|
"""
|
||||||
|
Sépare un compte Windows entre son préfixe et son nom de compte.
|
||||||
|
|
||||||
|
Exemples :
|
||||||
|
"FORMATION\\WSMANAGE30$"
|
||||||
|
-> ("FORMATION", "WSMANAGE30$")
|
||||||
|
|
||||||
|
"WSMANAGE30\\formation"
|
||||||
|
-> ("WSMANAGE30", "formation")
|
||||||
|
|
||||||
|
Si aucun préfixe n'est présent :
|
||||||
|
"formation"
|
||||||
|
-> ("", "formation")
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not account:
|
||||||
|
return "", ""
|
||||||
|
|
||||||
|
if "\\" in account:
|
||||||
|
return account.split("\\", 1)
|
||||||
|
|
||||||
|
return "", account
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Recherche des données GPResult dans le XML
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def _find_computer_results(root):
|
def _find_computer_results(root):
|
||||||
"""Recherche la section machine sans dependre des espaces de noms XML."""
|
"""
|
||||||
|
Recherche la section ComputerResults dans le document XML GPResult.
|
||||||
|
|
||||||
|
Les informations RSoP du contexte COMPUTER sont stockées sous ce nœud.
|
||||||
|
"""
|
||||||
|
|
||||||
for element in root.iter():
|
for element in root.iter():
|
||||||
|
|
||||||
if _clean_tag(element.tag) == "ComputerResults":
|
if _clean_tag(element.tag) == "ComputerResults":
|
||||||
return element
|
return element
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _get_gpos(computer_results):
|
# ---------------------------------------------------------------------------
|
||||||
"""Classe les GPO machine en appliquees et non appliquees.
|
# Analyse des GPO
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
Les doublons sont elimines selon le triplet nom/version annuaire/
|
def _get_gpos(scope_results):
|
||||||
version SYSVOL. Les GPO sans nom sont ignorees.
|
|
||||||
"""
|
"""
|
||||||
|
Extrait les GPO appliquées et refusées depuis un contexte GPResult.
|
||||||
|
|
||||||
|
Le XML GPResult peut contenir plusieurs nœuds nommés "GPO", y compris
|
||||||
|
des structures internes ou vides. Les entrées GPO sans nom sont ignorées.
|
||||||
|
|
||||||
|
Une GPO est considérée comme appliquée lorsque :
|
||||||
|
- elle est activée ;
|
||||||
|
- elle est valide ;
|
||||||
|
- le filtrage de sécurité / WMI l'autorise ;
|
||||||
|
- l'accès n'est pas refusé.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple:
|
||||||
|
applied_gpos: list[str]
|
||||||
|
denied_gpos: list[str]
|
||||||
|
"""
|
||||||
|
|
||||||
applied = []
|
applied = []
|
||||||
denied = []
|
denied = []
|
||||||
|
|
||||||
|
# Permet d'éviter les doublons de GPO présents dans le XML GPResult.
|
||||||
seen = set()
|
seen = set()
|
||||||
|
|
||||||
if computer_results is None:
|
if scope_results is None:
|
||||||
return applied, denied
|
return applied, denied
|
||||||
|
|
||||||
# Conserver la recherche recursive de la version de reference.
|
for element in scope_results.iter():
|
||||||
for element in computer_results.iter():
|
|
||||||
|
|
||||||
if _clean_tag(element.tag) != "GPO":
|
if _clean_tag(element.tag) != "GPO":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
name = _text(element, "Name")
|
name = _text(
|
||||||
|
element,
|
||||||
|
"Name"
|
||||||
|
)
|
||||||
|
|
||||||
|
# GPResult peut exposer des structures GPO internes sans nom.
|
||||||
|
# Elles ne doivent pas apparaître dans les données d'audit WAPT.
|
||||||
if not name:
|
if not name:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -114,6 +200,8 @@ def _get_gpos(computer_results):
|
|||||||
"VersionSysvol"
|
"VersionSysvol"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Le nom seul ne suffit pas toujours pour dédupliquer une GPO.
|
||||||
|
# Les versions AD et SYSVOL sont donc intégrées à son identité.
|
||||||
identity = (
|
identity = (
|
||||||
name,
|
name,
|
||||||
version_directory,
|
version_directory,
|
||||||
@@ -125,9 +213,6 @@ def _get_gpos(computer_results):
|
|||||||
|
|
||||||
seen.add(identity)
|
seen.add(identity)
|
||||||
|
|
||||||
# Une GPO est appliquee uniquement si les trois indicateurs
|
|
||||||
# positifs sont vrais et si aucun refus d'acces n'est indique.
|
|
||||||
# denied regroupe toutes les autres entrees retenues.
|
|
||||||
if (
|
if (
|
||||||
enabled
|
enabled
|
||||||
and valid
|
and valid
|
||||||
@@ -142,10 +227,191 @@ def _get_gpos(computer_results):
|
|||||||
return applied, denied
|
return applied, denied
|
||||||
|
|
||||||
|
|
||||||
def audit():
|
# ---------------------------------------------------------------------------
|
||||||
"""Exporte le GPResult machine, enregistre les donnees et retourne un statut."""
|
# Analyse des groupes de sécurité
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def _get_security_groups(scope_results, principal_name):
|
||||||
|
"""
|
||||||
|
Extrait et classe les groupes de sécurité présents dans le RSoP.
|
||||||
|
|
||||||
|
GPResult contient déjà les appartenances aux groupes de sécurité
|
||||||
|
effectivement utilisées lors de l'évaluation des stratégies de groupe.
|
||||||
|
Réutiliser ces informations évite d'effectuer une requête LDAP
|
||||||
|
supplémentaire depuis le poste.
|
||||||
|
|
||||||
|
Les groupes sont classés en quatre catégories :
|
||||||
|
|
||||||
|
domain:
|
||||||
|
Groupe dont le préfixe correspond au domaine du compte RSoP.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
FORMATION\\Domain Computers
|
||||||
|
|
||||||
|
local:
|
||||||
|
Groupes BUILTIN ou groupes préfixés par le nom du poste local.
|
||||||
|
|
||||||
|
Exemples :
|
||||||
|
BUILTIN\\Users
|
||||||
|
PC001\\Administrators
|
||||||
|
|
||||||
|
system:
|
||||||
|
Identités de sécurité Windows appartenant à NT AUTHORITY.
|
||||||
|
|
||||||
|
Exemples :
|
||||||
|
NT AUTHORITY\\Authenticated Users
|
||||||
|
NT AUTHORITY\\NETWORK
|
||||||
|
|
||||||
|
other:
|
||||||
|
Toute identité de sécurité qui ne peut pas être classée
|
||||||
|
de manière fiable dans l'une des catégories précédentes.
|
||||||
|
|
||||||
|
Important :
|
||||||
|
Le préfixe du compte n'est considéré comme un domaine AD que s'il
|
||||||
|
est différent du nom du poste local.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
FORMATION\\PC001$ -> FORMATION est considéré comme un domaine.
|
||||||
|
|
||||||
|
PC001\\localuser -> PC001 correspond au nom du poste ;
|
||||||
|
il s'agit donc d'un compte local et non d'un domaine AD.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict contenant :
|
||||||
|
domain
|
||||||
|
local
|
||||||
|
system
|
||||||
|
other
|
||||||
|
"""
|
||||||
|
|
||||||
|
groups = {
|
||||||
|
"domain": [],
|
||||||
|
"local": [],
|
||||||
|
"system": [],
|
||||||
|
"other": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
# Évite les doublons dans les noms de groupes.
|
||||||
|
seen = set()
|
||||||
|
|
||||||
|
if scope_results is None:
|
||||||
|
return groups
|
||||||
|
|
||||||
|
# Exemple :
|
||||||
|
# principal_name = "FORMATION\\WSMANAGE30$"
|
||||||
|
principal_domain, _ = _split_account(
|
||||||
|
principal_name
|
||||||
|
)
|
||||||
|
|
||||||
|
principal_domain = principal_domain.upper()
|
||||||
|
|
||||||
|
computer_name = os.environ.get(
|
||||||
|
"COMPUTERNAME",
|
||||||
|
""
|
||||||
|
).upper()
|
||||||
|
|
||||||
|
# Si le préfixe du compte correspond au nom de la machine,
|
||||||
|
# le compte est local.
|
||||||
|
# Dans ce cas, il n'existe pas de préfixe de domaine AD à utiliser
|
||||||
|
# pour classer les groupes.
|
||||||
|
ad_domain = ""
|
||||||
|
|
||||||
|
if (
|
||||||
|
principal_domain
|
||||||
|
and principal_domain != computer_name
|
||||||
|
):
|
||||||
|
ad_domain = principal_domain
|
||||||
|
|
||||||
|
for element in scope_results.iter():
|
||||||
|
|
||||||
|
if _clean_tag(element.tag) != "SecurityGroup":
|
||||||
|
continue
|
||||||
|
|
||||||
|
name = _text(
|
||||||
|
element,
|
||||||
|
"Name"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not name:
|
||||||
|
continue
|
||||||
|
|
||||||
|
name = name.strip()
|
||||||
|
|
||||||
|
key = name.lower()
|
||||||
|
|
||||||
|
if key in seen:
|
||||||
|
continue
|
||||||
|
|
||||||
|
seen.add(key)
|
||||||
|
|
||||||
|
upper_name = name.upper()
|
||||||
|
|
||||||
|
# Identités de sécurité intégrées à Windows.
|
||||||
|
if upper_name.startswith(
|
||||||
|
"NT AUTHORITY\\"
|
||||||
|
):
|
||||||
|
groups["system"].append(name)
|
||||||
|
|
||||||
|
# Groupes locaux intégrés.
|
||||||
|
elif upper_name.startswith(
|
||||||
|
"BUILTIN\\"
|
||||||
|
):
|
||||||
|
groups["local"].append(name)
|
||||||
|
|
||||||
|
# Groupes explicitement préfixés par le nom du poste local.
|
||||||
|
elif (
|
||||||
|
computer_name
|
||||||
|
and upper_name.startswith(
|
||||||
|
computer_name + "\\"
|
||||||
|
)
|
||||||
|
):
|
||||||
|
groups["local"].append(name)
|
||||||
|
|
||||||
|
# Groupes correspondant au vrai préfixe de domaine AD
|
||||||
|
# du compte évalué dans le RSoP.
|
||||||
|
elif (
|
||||||
|
ad_domain
|
||||||
|
and upper_name.startswith(
|
||||||
|
ad_domain + "\\"
|
||||||
|
)
|
||||||
|
):
|
||||||
|
groups["domain"].append(name)
|
||||||
|
|
||||||
|
# Les identités inconnues sont conservées plutôt que d'être
|
||||||
|
# classées à tort comme groupes de domaine.
|
||||||
|
else:
|
||||||
|
groups["other"].append(name)
|
||||||
|
|
||||||
|
# Un tri alphabétique stable améliore la lisibilité de l'audit
|
||||||
|
# et évite des changements WAPT inutiles causés uniquement
|
||||||
|
# par un ordre différent dans les listes.
|
||||||
|
for category in groups:
|
||||||
|
|
||||||
|
groups[category] = sorted(
|
||||||
|
groups[category],
|
||||||
|
key=lambda x: x.lower()
|
||||||
|
)
|
||||||
|
|
||||||
|
return groups
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Audit WAPT
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def audit():
|
||||||
|
"""
|
||||||
|
Exécute GPResult pour le contexte COMPUTER et publie un résultat
|
||||||
|
structuré et compact dans les données d'audit WAPT.
|
||||||
|
|
||||||
|
Le résultat contient :
|
||||||
|
- les informations du poste ;
|
||||||
|
- les GPO appliquées ;
|
||||||
|
- les GPO refusées ;
|
||||||
|
- les groupes AD ;
|
||||||
|
- le détail complet des groupes de sécurité classés.
|
||||||
|
"""
|
||||||
|
|
||||||
# Nom temporaire fixe conserve de la version fournie.
|
|
||||||
xml_file = os.path.join(
|
xml_file = os.path.join(
|
||||||
tempfile.gettempdir(),
|
tempfile.gettempdir(),
|
||||||
"wapt-gpresult-computer.xml"
|
"wapt-gpresult-computer.xml"
|
||||||
@@ -153,18 +419,26 @@ def audit():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
# Eviter de lire le rapport d'une execution precedente.
|
# Supprime un éventuel rapport restant d'une exécution précédente.
|
||||||
if os.path.isfile(xml_file):
|
if os.path.isfile(xml_file):
|
||||||
os.remove(xml_file)
|
os.remove(xml_file)
|
||||||
|
|
||||||
# /SCOPE COMPUTER cible les GPO machine ; /X produit le XML ;
|
gpresult_path = makepath(
|
||||||
# /F autorise le remplacement du fichier de destination.
|
system32(),
|
||||||
command = '"%s" /SCOPE COMPUTER /X "%s" /F' % (
|
"gpresult.exe"
|
||||||
makepath(system32(), "gpresult.exe"),
|
|
||||||
xml_file
|
|
||||||
)
|
)
|
||||||
|
|
||||||
print("Running GPResult COMPUTER...")
|
command = (
|
||||||
|
'"%s" /SCOPE COMPUTER /X "%s" /F'
|
||||||
|
% (
|
||||||
|
gpresult_path,
|
||||||
|
xml_file
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
print(
|
||||||
|
"Running GPResult COMPUTER..."
|
||||||
|
)
|
||||||
|
|
||||||
run(
|
run(
|
||||||
command,
|
command,
|
||||||
@@ -172,26 +446,53 @@ def audit():
|
|||||||
return_stderr=False
|
return_stderr=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# GPResult peut théoriquement terminer son exécution
|
||||||
|
# sans avoir généré le fichier XML attendu.
|
||||||
if not os.path.isfile(xml_file):
|
if not os.path.isfile(xml_file):
|
||||||
|
|
||||||
raise Exception(
|
raise Exception(
|
||||||
"GPResult did not generate XML report"
|
"GPResult did not generate XML report"
|
||||||
)
|
)
|
||||||
|
|
||||||
tree = ET.parse(xml_file)
|
# Analyse du XML généré par GPResult.
|
||||||
|
tree = ET.parse(
|
||||||
|
xml_file
|
||||||
|
)
|
||||||
|
|
||||||
root = tree.getroot()
|
root = tree.getroot()
|
||||||
|
|
||||||
computer_results = _find_computer_results(root)
|
computer_results = _find_computer_results(
|
||||||
|
root
|
||||||
|
)
|
||||||
|
|
||||||
if computer_results is None:
|
if computer_results is None:
|
||||||
|
|
||||||
raise Exception(
|
raise Exception(
|
||||||
"ComputerResults section not found"
|
"ComputerResults section not found"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Compte ordinateur évalué par GPResult.
|
||||||
|
#
|
||||||
|
# Exemple :
|
||||||
|
# FORMATION\\WSMANAGE30$
|
||||||
|
rsop_computer = _text(
|
||||||
|
computer_results,
|
||||||
|
"Name"
|
||||||
|
)
|
||||||
|
|
||||||
applied_gpos, denied_gpos = _get_gpos(
|
applied_gpos, denied_gpos = _get_gpos(
|
||||||
computer_results
|
computer_results
|
||||||
)
|
)
|
||||||
|
|
||||||
# Essayer DomainName, puis Domain si aucune valeur n'est trouvee.
|
security_groups = _get_security_groups(
|
||||||
|
computer_results,
|
||||||
|
rsop_computer
|
||||||
|
)
|
||||||
|
|
||||||
|
# Domaine DNS fourni par GPResult.
|
||||||
|
#
|
||||||
|
# Exemple :
|
||||||
|
# ad.formation.lan
|
||||||
domain = _text(
|
domain = _text(
|
||||||
computer_results,
|
computer_results,
|
||||||
"DomainName"
|
"DomainName"
|
||||||
@@ -203,16 +504,32 @@ def audit():
|
|||||||
"Domain"
|
"Domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
account_domain, account_name = _split_account(
|
||||||
|
rsop_computer
|
||||||
|
)
|
||||||
|
|
||||||
|
# Structure d'audit WAPT volontairement compacte
|
||||||
|
# et facilement exploitable en SQL / reporting.
|
||||||
audit_data = {
|
audit_data = {
|
||||||
|
|
||||||
"status": "OK",
|
"status": "OK",
|
||||||
|
|
||||||
"computer": {
|
"computer": {
|
||||||
|
|
||||||
"name": os.environ.get(
|
"name": os.environ.get(
|
||||||
"COMPUTERNAME",
|
"COMPUTERNAME",
|
||||||
""
|
""
|
||||||
),
|
),
|
||||||
|
|
||||||
|
# Compte de sécurité complet du poste retourné par GPResult.
|
||||||
|
"account": rsop_computer,
|
||||||
|
|
||||||
|
# Préfixe du compte au format NetBIOS.
|
||||||
|
"account_domain": account_domain,
|
||||||
|
|
||||||
|
# Domaine DNS lorsqu'il est disponible.
|
||||||
"domain": domain,
|
"domain": domain,
|
||||||
|
|
||||||
"site": _text(
|
"site": _text(
|
||||||
computer_results,
|
computer_results,
|
||||||
"Site"
|
"Site"
|
||||||
@@ -220,21 +537,52 @@ def audit():
|
|||||||
},
|
},
|
||||||
|
|
||||||
"summary": {
|
"summary": {
|
||||||
"applied_gpo_count": len(applied_gpos),
|
|
||||||
"denied_gpo_count": len(denied_gpos),
|
"applied_gpo_count": len(
|
||||||
|
applied_gpos
|
||||||
|
),
|
||||||
|
|
||||||
|
"denied_gpo_count": len(
|
||||||
|
denied_gpos
|
||||||
|
),
|
||||||
|
|
||||||
"total_gpo_count": (
|
"total_gpo_count": (
|
||||||
len(applied_gpos)
|
len(applied_gpos)
|
||||||
+ len(denied_gpos)
|
+ len(denied_gpos)
|
||||||
),
|
),
|
||||||
|
|
||||||
|
"domain_group_count": len(
|
||||||
|
security_groups["domain"]
|
||||||
|
),
|
||||||
|
|
||||||
|
"local_group_count": len(
|
||||||
|
security_groups["local"]
|
||||||
|
),
|
||||||
|
|
||||||
|
"system_group_count": len(
|
||||||
|
security_groups["system"]
|
||||||
|
),
|
||||||
|
|
||||||
|
"other_group_count": len(
|
||||||
|
security_groups["other"]
|
||||||
|
),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
# Les GPO sont conservées sous forme de simples listes de noms
|
||||||
|
# afin de faciliter leur exploitation en SQL / reporting.
|
||||||
"applied_gpos": applied_gpos,
|
"applied_gpos": applied_gpos,
|
||||||
|
|
||||||
"denied_gpos": denied_gpos,
|
"denied_gpos": denied_gpos,
|
||||||
|
|
||||||
|
# Champ pratique contenant uniquement les groupes AD identifiés.
|
||||||
|
"domain_groups":
|
||||||
|
security_groups["domain"],
|
||||||
|
|
||||||
|
# Le classement complet est conservé pour le diagnostic.
|
||||||
|
"security_groups":
|
||||||
|
security_groups,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Transmettre le dictionnaire directement pour conserver une
|
|
||||||
# donnee structuree, plutot qu'une chaine de texte JSON.
|
|
||||||
WAPT.write_audit_data_if_changed(
|
WAPT.write_audit_data_if_changed(
|
||||||
AUDIT_SECTION,
|
AUDIT_SECTION,
|
||||||
AUDIT_NAME,
|
AUDIT_NAME,
|
||||||
@@ -244,19 +592,28 @@ def audit():
|
|||||||
)
|
)
|
||||||
|
|
||||||
print(
|
print(
|
||||||
"GPResult COMPUTER: %s applied / %s denied"
|
"GPResult COMPUTER: "
|
||||||
|
"%s applied / %s denied"
|
||||||
% (
|
% (
|
||||||
len(applied_gpos),
|
len(applied_gpos),
|
||||||
len(denied_gpos)
|
len(denied_gpos)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
print(
|
||||||
|
"AD groups: %s"
|
||||||
|
% len(
|
||||||
|
security_groups["domain"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
||||||
# La meme cle est mise a jour avec l'erreur : les anciennes
|
# Enregistre également l'erreur dans les données d'audit WAPT
|
||||||
# listes ne sont pas recopiees comme resultat de cet audit.
|
# afin qu'elle soit visible depuis la console et pas uniquement
|
||||||
|
# dans les logs locaux de l'agent.
|
||||||
WAPT.write_audit_data_if_changed(
|
WAPT.write_audit_data_if_changed(
|
||||||
AUDIT_SECTION,
|
AUDIT_SECTION,
|
||||||
AUDIT_NAME,
|
AUDIT_NAME,
|
||||||
@@ -277,10 +634,12 @@ def audit():
|
|||||||
|
|
||||||
finally:
|
finally:
|
||||||
|
|
||||||
# Nettoyage tente apres succes comme apres erreur.
|
# Le fichier XML est uniquement un fichier de travail temporaire.
|
||||||
# Un echec de suppression est ignore dans la version conservee.
|
# Il n'a pas vocation à rester sur le poste.
|
||||||
try:
|
try:
|
||||||
|
|
||||||
if os.path.isfile(xml_file):
|
if os.path.isfile(xml_file):
|
||||||
os.remove(xml_file)
|
os.remove(xml_file)
|
||||||
except:
|
|
||||||
|
except Exception:
|
||||||
pass
|
pass
|
||||||
Reference in new issue
Block a user