runv-server

server tooling for runv.club
Log | Files | Refs | README

perm1.py (3882B)


      1 #!/usr/bin/env python3
      2 from __future__ import annotations
      3 
      4 import argparse
      5 import logging
      6 import os
      7 import pwd
      8 import sys
      9 from pathlib import Path
     10 
     11 _SCRIPT_DIR = Path(__file__).resolve().parent
     12 if str(_SCRIPT_DIR) not in sys.path:
     13     sys.path.insert(0, str(_SCRIPT_DIR))
     14 
     15 from admin_guard import ensure_admin_cli
     16 import runv_jail as rj
     17 
     18 EXCLUDE_NAMES = frozenset({"nobody", "pmurad-admin", "entre"})
     19 
     20 
     21 def setup_logging(verbose: bool) -> logging.Logger:
     22     log = logging.getLogger("perm1")
     23     log.setLevel(logging.DEBUG if verbose else logging.INFO)
     24     log.handlers.clear()
     25     h = logging.StreamHandler(sys.stderr)
     26     h.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
     27     log.addHandler(h)
     28     return log
     29 
     30 
     31 def iter_targets(only_user: str | None):
     32     if only_user:
     33         yield pwd.getpwnam(only_user)
     34         return
     35     for pw in pwd.getpwall():
     36         if pw.pw_uid < 1000:
     37             continue
     38         if pw.pw_name in EXCLUDE_NAMES or rj.jail_skip_username(pw.pw_name):
     39             continue
     40         yield pw
     41 
     42 
     43 def main(argv: list[str] | None = None) -> int:
     44     p = argparse.ArgumentParser(
     45         description="Aplica runv-jailed + jail /srv/jail/<user> a contas existentes (uid>=1000).",
     46     )
     47     p.add_argument("--dry-run", action="store_true", help="só listar utilizadores e ações previstas")
     48     p.add_argument("--verbose", "-v", action="store_true", help="log detalhado")
     49     p.add_argument(
     50         "--only-user",
     51         metavar="U",
     52         default=None,
     53         help="processar apenas este utilizador (ainda sujeito a exclusões)",
     54     )
     55     p.add_argument(
     56         "--jk-profile",
     57         default="extendedshell",
     58         metavar="P",
     59         choices=("extendedshell", "basicshell"),
     60         help="perfil Jailkit para jk_init quando o jail ainda não tem bin/ (default: extendedshell)",
     61     )
     62     p.add_argument(
     63         "--no-jk-init",
     64         action="store_true",
     65         help="não executar jk_init; exige jail já com bin/ (só grupo + home no jail + bind + fstab)",
     66     )
     67     args = p.parse_args(argv)
     68     ensure_admin_cli(
     69         script_name=Path(__file__).name,
     70         dry_run=bool(args.dry_run),
     71     )
     72 
     73     log = setup_logging(args.verbose)
     74 
     75     if os.geteuid() != 0 and not args.dry_run:
     76         log.error("execute como root (ou use --dry-run)")
     77         return 2
     78 
     79     if args.only_user:
     80         u = args.only_user.strip()
     81         if u in EXCLUDE_NAMES or rj.jail_skip_username(u):
     82             log.error("utilizador %r está excluído desta ferramenta", u)
     83             return 1
     84 
     85     try:
     86         targets = list(iter_targets(args.only_user))
     87     except KeyError as e:
     88         log.error("utilizador desconhecido: %s", e)
     89         return 1
     90 
     91     if not targets:
     92         log.warning("nenhum utilizador corresponde aos critérios")
     93         return 0
     94 
     95     for pw in targets:
     96         home = Path(pw.pw_dir)
     97         log.info("--- %s (uid=%s) home=%s", pw.pw_name, pw.pw_uid, home)
     98         if args.dry_run:
     99             if rj.jail_skip_username(pw.pw_name):
    100                 log.info("[dry-run] omitir (exclusão)")
    101             else:
    102                 log.info(
    103                     "[dry-run] usermod -aG runv-jailed + jail em /srv/jail/%s "
    104                     "(jk_profile=%s, no_jk_init=%s)",
    105                     pw.pw_name,
    106                     args.jk_profile,
    107                     args.no_jk_init,
    108                 )
    109             continue
    110         try:
    111             rj.ensure_runv_jail_for_user(
    112                 pw.pw_name,
    113                 home,
    114                 no_jail=False,
    115                 log=log,
    116                 jk_profile=args.jk_profile,
    117                 no_jk_init=args.no_jk_init,
    118             )
    119         except Exception as e:
    120             log.error("falha para %s: %s", pw.pw_name, e)
    121             return 3
    122 
    123     log.info("concluído (%d utilizador(es))", len(targets))
    124     return 0
    125 
    126 
    127 if __name__ == "__main__":
    128     raise SystemExit(main())