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())