Fix output format
This commit is contained in:
@@ -58,7 +58,7 @@ prometheus-exporter
|
|||||||
proxy
|
proxy
|
||||||
rdma
|
rdma
|
||||||
root
|
root
|
||||||
runit
|
# runit
|
||||||
salt
|
salt
|
||||||
sambashare
|
sambashare
|
||||||
saned
|
saned
|
||||||
@@ -80,7 +80,6 @@ systemd-timesync
|
|||||||
tape
|
tape
|
||||||
tcpdump
|
tcpdump
|
||||||
tty
|
tty
|
||||||
uallt_e
|
|
||||||
users
|
users
|
||||||
utempter
|
utempter
|
||||||
utmp
|
utmp
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@@ -78,13 +78,6 @@ def main():
|
|||||||
for user in users.values():
|
for user in users.values():
|
||||||
user.email = f"{user.name}@{args.email_domain}"
|
user.email = f"{user.name}@{args.email_domain}"
|
||||||
|
|
||||||
if not args.output_dir.exists():
|
|
||||||
args.output_dir.mkdir(parents=True)
|
|
||||||
user_dir = args.output_dir / "users"
|
|
||||||
user_dir.mkdir(exist_ok=True)
|
|
||||||
group_dir = args.output_dir / "groups"
|
|
||||||
group_dir.mkdir(exist_ok=True)
|
|
||||||
|
|
||||||
# print_group_stats(groups, users)
|
# print_group_stats(groups, users)
|
||||||
|
|
||||||
for user in users.values():
|
for user in users.values():
|
||||||
@@ -94,12 +87,7 @@ def main():
|
|||||||
if user.name in shadow:
|
if user.name in shadow:
|
||||||
user.set_shadow_entry(shadow[user.name])
|
user.set_shadow_entry(shadow[user.name])
|
||||||
|
|
||||||
with open(args.output_dir / "users" / f"{user.name}.json", "w") as f:
|
output_to_directory(users, groups, args.output_dir)
|
||||||
json.dump(user.to_systemd_user_record(), f, indent=2)
|
|
||||||
|
|
||||||
for group in groups.values():
|
|
||||||
with open(args.output_dir / "groups" / f"{group.name}.json", "w") as f:
|
|
||||||
json.dump(group.to_systemd_group_record(), f, indent=2)
|
|
||||||
|
|
||||||
|
|
||||||
def ensure_no_overlapping_uids(users: dict[str, User]):
|
def ensure_no_overlapping_uids(users: dict[str, User]):
|
||||||
@@ -327,13 +315,16 @@ class User:
|
|||||||
if self.memberOf:
|
if self.memberOf:
|
||||||
result["memberOf"] = self.memberOf
|
result["memberOf"] = self.memberOf
|
||||||
|
|
||||||
if self.password is not None:
|
|
||||||
result["privileged"] = {
|
|
||||||
"hashedPassword": self.password,
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def to_systemd_privileged_user_record(self) -> dict[str, Any] | None:
|
||||||
|
if self.password is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return {
|
||||||
|
"hashedPassword": self.password,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Group:
|
class Group:
|
||||||
@@ -348,6 +339,10 @@ class Group:
|
|||||||
"members": self.members,
|
"members": self.members,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# TODO: parse gshadow
|
||||||
|
def to_systemd_privileged_group_record(self) -> dict[str, Any] | None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def print_group_stats(
|
def print_group_stats(
|
||||||
groups: dict[str, Group],
|
groups: dict[str, Group],
|
||||||
@@ -373,5 +368,80 @@ def print_group_stats(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def output_to_directory(
|
||||||
|
users: dict[str, User],
|
||||||
|
groups: dict[str, Group],
|
||||||
|
output_dir: Path,
|
||||||
|
):
|
||||||
|
if not output_dir.exists():
|
||||||
|
output_dir.mkdir(parents=True)
|
||||||
|
|
||||||
|
for user in users.values():
|
||||||
|
user_record = user.to_systemd_user_record()
|
||||||
|
with open(output_dir / f"{user.name}.user", "w") as f:
|
||||||
|
json.dump(user_record, f, indent=2)
|
||||||
|
|
||||||
|
symlink_path = output_dir / f"{user.uid}.user"
|
||||||
|
if symlink_path.exists():
|
||||||
|
symlink_path.unlink()
|
||||||
|
symlink_path.symlink_to(f"./{user.name}.user")
|
||||||
|
|
||||||
|
privileged_user_record = user.to_systemd_privileged_user_record()
|
||||||
|
if privileged_user_record:
|
||||||
|
priv_path = output_dir / f"{user.name}.user-privileged"
|
||||||
|
priv_path.touch(exist_ok=True)
|
||||||
|
priv_path.chmod(0o600)
|
||||||
|
with open(priv_path, "w") as f:
|
||||||
|
json.dump(privileged_user_record, f, indent=2)
|
||||||
|
|
||||||
|
symlink_path = output_dir / f"{user.uid}.user-privileged"
|
||||||
|
if symlink_path.exists():
|
||||||
|
symlink_path.unlink()
|
||||||
|
symlink_path.symlink_to(f"./{user.name}.user-privileged")
|
||||||
|
|
||||||
|
for group in groups.values():
|
||||||
|
group_record = group.to_systemd_group_record()
|
||||||
|
with open(output_dir / f"{group.name}.group", "w") as f:
|
||||||
|
json.dump(group_record, f, indent=2)
|
||||||
|
|
||||||
|
symlink_path = output_dir / f"{group.gid}.group"
|
||||||
|
if symlink_path.exists():
|
||||||
|
symlink_path.unlink()
|
||||||
|
symlink_path.symlink_to(f"./{group.name}.group")
|
||||||
|
|
||||||
|
privileged_group_record = group.to_systemd_privileged_group_record()
|
||||||
|
if privileged_group_record:
|
||||||
|
priv_path = output_dir / f"{group.name}.group-privileged"
|
||||||
|
priv_path.touch(exist_ok=True)
|
||||||
|
priv_path.chmod(0o600)
|
||||||
|
with open(priv_path, "w") as f:
|
||||||
|
json.dump(privileged_group_record, f, indent=2)
|
||||||
|
|
||||||
|
symlink_path = output_dir / f"{group.gid}.group-privileged"
|
||||||
|
if symlink_path.exists():
|
||||||
|
symlink_path.unlink()
|
||||||
|
symlink_path.symlink_to(f"./{group.name}.group-privileged")
|
||||||
|
|
||||||
|
groups_by_gid = {group.gid: group for group in groups.values()}
|
||||||
|
for user in users.values():
|
||||||
|
primary_group = groups_by_gid.get(user.gid)
|
||||||
|
if not primary_group:
|
||||||
|
print(
|
||||||
|
f"Warning: User {user.name} has primary GID {user.gid} which does not correspond to any group"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
with open(
|
||||||
|
output_dir / f"{user.name}:{primary_group.name}.membership", "w"
|
||||||
|
) as f:
|
||||||
|
json.dump({}, f)
|
||||||
|
|
||||||
|
for group in groups.values():
|
||||||
|
if user.name in group.members:
|
||||||
|
with open(
|
||||||
|
output_dir / f"{user.name}:{group.name}.membership", "w"
|
||||||
|
) as f:
|
||||||
|
json.dump({}, f)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Reference in New Issue
Block a user