Parse group and shadow

This commit is contained in:
2026-05-29 09:10:58 +09:00
parent 00b716563e
commit c156a68115
4 changed files with 123 additions and 3 deletions
+65 -3
View File
@@ -7,13 +7,23 @@ from pathlib import Path
def main():
parser = argparse.ArgumentParser(
description="Convert a passwd file to a directory of systemd JSON user records.",
description="Convert a passwd/group/shadow file to a directory of systemd JSON user records.",
)
parser.add_argument(
"passwd_file",
type=Path,
help="Path to the passwd file.",
)
parser.add_argument(
"group_file",
type=Path,
help="Path to the group file.",
)
parser.add_argument(
"shadow_file",
type=Path,
help="Path to the shadow file.",
)
parser.add_argument(
"output_dir",
type=Path,
@@ -22,10 +32,18 @@ def main():
args = parser.parse_args()
parsed_users = parse_passwd_file(args.passwd_file)
parsed_groups = parse_group_file(args.group_file)
parsed_shadow = parse_shadow_file(args.shadow_file)
for user in parsed_users:
print(json.dumps(user, indent=2))
for group in parsed_groups:
print(json.dumps(group, indent=2))
for shadow_entry in parsed_shadow:
print(json.dumps(shadow_entry, indent=2))
def parse_passwd_file(passwd_file: Path) -> list[dict]:
users = []
@@ -41,7 +59,7 @@ def parse_passwd_file(passwd_file: Path) -> list[dict]:
"name": parts[0],
"uid": int(parts[2]),
"gid": int(parts[3]),
"gecos": parse_gecos(parts[4]),
"gecos": parse_passwd_gecos(parts[4]),
"home": parts[5],
"shell": parts[6],
}
@@ -49,7 +67,7 @@ def parse_passwd_file(passwd_file: Path) -> list[dict]:
return users
def parse_gecos(gecos: str) -> dict:
def parse_passwd_gecos(gecos: str) -> dict:
parts = gecos.split(",")
return {
"full_name": parts[0] if len(parts) > 0 else "",
@@ -60,5 +78,49 @@ def parse_gecos(gecos: str) -> dict:
}
def parse_group_file(group_file: Path) -> list[dict]:
groups = []
with group_file.open("r") as f:
for line in f:
if line.startswith("#") or not line.strip():
continue
parts = line.strip().split(":")
if len(parts) < 4:
print(f"Warning: Skipping malformed line: {line.strip()}")
continue
group = {
"name": parts[0],
"gid": int(parts[2]),
"members": parts[3].split(",") if parts[3] else [],
}
groups.append(group)
return groups
def parse_shadow_file(shadow_file: Path) -> list[dict]:
shadow_entries = []
with shadow_file.open("r") as f:
for line in f:
if line.startswith("#") or not line.strip():
continue
parts = line.strip().split(":")
if len(parts) < 9:
print(f"Warning: Skipping malformed line: {line.strip()}")
continue
shadow_entry = {
"name": parts[0],
"password": parts[1],
"last_change": int(parts[2]) if parts[2].isdigit() else None,
"min_days": int(parts[3]) if parts[3].isdigit() else None,
"max_days": int(parts[4]) if parts[4].isdigit() else None,
"warn_days": int(parts[5]) if parts[5].isdigit() else None,
"inactive_days": int(parts[6]) if parts[6].isdigit() else None,
"expire_date": int(parts[7]) if parts[7].isdigit() else None,
"reserved": parts[8],
}
shadow_entries.append(shadow_entry)
return shadow_entries
if __name__ == "__main__":
main()