Parse group and shadow
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
root:x:0:
|
||||
daemon:x:1:
|
||||
bin:x:2:
|
||||
sys:x:3:
|
||||
games:x:60:
|
||||
man:x:12:
|
||||
lp:x:7:
|
||||
mail:x:8:
|
||||
news:x:9:
|
||||
uucp:x:10:
|
||||
proxy:x:13:
|
||||
www-data:x:33:
|
||||
backup:x:34:
|
||||
list:x:38:
|
||||
irc:x:39:
|
||||
gnats:x:41:
|
||||
nobody:x:65534:
|
||||
systemd-timesync:x:101:
|
||||
systemd-network:x:103:user1
|
||||
systemd-resolve:x:104:user1,user2
|
||||
messagebus:x:105:
|
||||
avahi:x:109:
|
||||
saned:x:112:
|
||||
xrdp:x:114:
|
||||
|
||||
user1:x:1000:
|
||||
user2:x:1001:
|
||||
user3:x:1002:
|
||||
@@ -0,0 +1,30 @@
|
||||
root:!*:1::::::
|
||||
daemon:!*:1::::::
|
||||
bin:!*:1::::::
|
||||
sys:!*:1::::::
|
||||
sync:!*:1::::::
|
||||
games:!*:1::::::
|
||||
man:!*:1::::::
|
||||
lp:!*:1::::::
|
||||
mail:!*:1::::::
|
||||
news:!*:1::::::
|
||||
uucp:!*:1::::::
|
||||
proxy:!*:1::::::
|
||||
www-data:!*:1::::::
|
||||
backup:!*:1::::::
|
||||
list:!*:1::::::
|
||||
irc:!*:1::::::
|
||||
gnats:!*:1::::::
|
||||
nobody:!*:1::::::
|
||||
_apt:!*:1::::::
|
||||
systemd-timesync:!*:1::::::
|
||||
systemd-network:!*:1::::::
|
||||
systemd-resolve:!*:1::::::
|
||||
messagebus:!*:1::::::
|
||||
avahi:!*:1::::::
|
||||
saned:!*:1::::::
|
||||
xrdp:!*:1::::::
|
||||
|
||||
user1:$y$j9T$gfNWp8nhIYxJtL7yy7myb0$LAsxtu.24imcyO5CH0xOL/G6Ii5LlLWnAJ.XL8CPYv3:20000::::::
|
||||
user2:$y$j9T$90l8J./nwd7sRU/HOyVtg.$f/M1K5evMFp0K2NYIjN257YHMUlg0wG/Sst1LXy2g3C:20001::::::
|
||||
user3:$y$j9T$lekKJIXaaL/24EvKehybL1$MSS0OHfiCTgcdExEDqaEsGFaYOphApGVV8fXrs.U1C5:20002::::::
|
||||
Reference in New Issue
Block a user