摘要:用于提取linux用户主目录代码,可用于任意文件读取遍历linux用户主目录。

import posixpath
from typing import Dict, List

SYSTEM_SHELL_KEYWORDS = (
    "nologin",
    "false",
    "sync",
    "halt",
    "shutdown",
)

SYSTEM_HOME_PREFIXES = (
    "/bin",
    "/dev",
    "/etc",
    "/lib",
    "/lib64",
    "/nonexistent",
    "/proc",
    "/run",
    "/sbin",
    "/snap",
    "/srv",
    "/sys",
    "/tmp",
    "/usr",
    "/var",
)

def normalize_relative_home_item(item: str) -> str:
    item = item.strip()
    item = item.lstrip("/")
    item = posixpath.normpath(item)
    if item in (".", ""):
        raise ValueError("home_path 中存在空路径")
    if item.startswith("../") or item == "..":
        raise ValueError(f"home_path 不能包含向上跳目录: {item}")
    return item


def should_keep_user(username: str, uid: int, home: str, shell: str) -> bool:
    home = home.strip()
    shell = shell.strip().lower()

    if not home.startswith("/"):
        return False

    if any(keyword in shell for keyword in SYSTEM_SHELL_KEYWORDS):
        return False

    if home == "/root":
        return True

    if home.startswith("/home/") or home.startswith("/Users/"):
        return True

    if uid >= 1000 and not home.startswith(SYSTEM_HOME_PREFIXES):
        return True

    return False


def parse_passwd_for_user_homes(passwd_text: str) -> List[Dict[str, str]]:
    users = []
    seen = set()

    for raw_line in passwd_text.splitlines():
        line = raw_line.strip()

        if not line or line.startswith("#"):
            continue

        parts = line.split(":")
        if len(parts) < 7:
            continue

        username = parts[0]
        try:
            uid = int(parts[2])
        except ValueError:
            continue
        home = parts[5].strip()
        shell = parts[6].strip()

        if not should_keep_user(username, uid, home, shell):
            continue

        key = (username, home)
        if key in seen:
            continue
        seen.add(key)
        users.append(
            {
                "username": username,
                "uid": str(uid),
                "home": posixpath.normpath(home),
                "shell": shell,
            }
        )
    return users


password_text = '''
root@hcss-ecs-a96f:~# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
'''
result = parse_passwd_for_user_homes(password_text)
print(result)