
Kod: Tümünü seç
"""
win_acl_manager.py
Windows File/Directory ACL Manager
Supports: list, modify, reset, lock, force-delete permissions
Backend: pywin32 (win32security) with ctypes fallback
Interface: CLI (argparse) + interactive menu fallback
"""
import os
import sys
import stat
import argparse
import shutil
import ctypes
from pathlib import Path
# ---------------------------------------------------------------------------
# Python venv bootstrapper
# ---------------------------------------------------------------------------
VENV_DIR = os.path.join(os.path.expanduser("~"), "python-toolchain")
_candidates = ["Scripts/python.exe", "bin/python3", "bin/python"]
if os.path.isdir(VENV_DIR) and sys.executable not in [
os.path.abspath(os.path.join(VENV_DIR, c)) for c in _candidates
]:
for _c in _candidates:
_venv_py = os.path.join(VENV_DIR, _c)
if os.path.isfile(_venv_py):
os.execv(_venv_py, [_venv_py] + sys.argv)
# ---------------------------------------------------------------------------
# Backend detection
# ---------------------------------------------------------------------------
try:
import win32security
import win32api
import win32con
import ntsecuritycon as nsc
BACKEND = "pywin32"
except ImportError:
BACKEND = "ctypes"
# ---------------------------------------------------------------------------
# Privilege helpers
# ---------------------------------------------------------------------------
def _is_admin() -> bool:
"""Return True if the current process has administrator privileges."""
try:
return ctypes.windll.shell32.IsUserAnAdmin() != 0
except Exception:
return False
def _enable_privilege_pywin32(privilege_name: str) -> bool:
"""Enable a Windows privilege via pywin32."""
try:
hToken = win32security.OpenProcessToken(
win32api.GetCurrentProcess(),
win32con.TOKEN_ADJUST_PRIVILEGES | win32con.TOKEN_QUERY,
)
luid = win32security.LookupPrivilegeValue(None, privilege_name)
win32security.AdjustTokenPrivileges(
hToken, False,
[(luid, win32con.SE_PRIVILEGE_ENABLED)]
)
return True
except Exception:
return False
def _enable_privilege_ctypes(privilege_name: str) -> bool:
"""Enable a Windows privilege via ctypes."""
SE_PRIVILEGE_ENABLED = 0x00000002
TOKEN_ADJUST_PRIVILEGES = 0x0020
TOKEN_QUERY = 0x0008
class LUID(ctypes.Structure):
_fields_ = [("LowPart", ctypes.c_ulong), ("HighPart", ctypes.c_long)]
class LUID_AND_ATTRIBUTES(ctypes.Structure):
_fields_ = [("Luid", LUID), ("Attributes", ctypes.c_ulong)]
class TOKEN_PRIVILEGES(ctypes.Structure):
_fields_ = [
("PrivilegeCount", ctypes.c_ulong),
("Privileges", LUID_AND_ATTRIBUTES * 1),
]
advapi32 = ctypes.windll.advapi32
kernel32 = ctypes.windll.kernel32
hToken = ctypes.c_void_p()
hProcess = kernel32.GetCurrentProcess()
if not advapi32.OpenProcessToken(
hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ctypes.byref(hToken)
):
return False
luid = LUID()
if not advapi32.LookupPrivilegeValueW(None, privilege_name, ctypes.byref(luid)):
kernel32.CloseHandle(hToken)
return False
tp = TOKEN_PRIVILEGES()
tp.PrivilegeCount = 1
tp.Privileges[0].Luid = luid
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED
result = advapi32.AdjustTokenPrivileges(
hToken, False, ctypes.byref(tp),
ctypes.sizeof(tp), None, None
)
kernel32.CloseHandle(hToken)
return result != 0
def enable_privilege(privilege_name: str) -> bool:
if BACKEND == "pywin32":
return _enable_privilege_pywin32(privilege_name)
return _enable_privilege_ctypes(privilege_name)
# ---------------------------------------------------------------------------
# ACL list / read
# ---------------------------------------------------------------------------
def _ace_mask_to_str(mask: int) -> str:
"""
Convert an ACE access mask to a human-readable string.
Evaluation order is most-specific first: FULL must be checked
before READ/WRITE/EXECUTE because those bits are all contained
within FILE_ALL_ACCESS, causing false READ-only matches when
the account actually holds full control.
"""
if BACKEND == "pywin32":
# FILE_ALL_ACCESS on Windows includes all standard + specific +
# generic rights. Test it first before decomposing into parts.
FILE_ALL_ACCESS = 0x001F01FF # standard definition; nsc value identical
if (mask & FILE_ALL_ACCESS) == FILE_ALL_ACCESS:
return "FULL"
parts = []
# Ordered from broadest remaining to narrowest
checks = [
(nsc.FILE_GENERIC_READ | nsc.FILE_GENERIC_WRITE |
nsc.FILE_GENERIC_EXECUTE, "READ|WRITE|EXECUTE"),
(nsc.FILE_GENERIC_READ | nsc.FILE_GENERIC_WRITE, "READ|WRITE"),
(nsc.FILE_GENERIC_READ | nsc.FILE_GENERIC_EXECUTE,"READ|EXECUTE"),
(nsc.FILE_GENERIC_WRITE | nsc.FILE_GENERIC_EXECUTE,"WRITE|EXECUTE"),
(nsc.FILE_GENERIC_READ, "READ"),
(nsc.FILE_GENERIC_WRITE, "WRITE"),
(nsc.FILE_GENERIC_EXECUTE, "EXECUTE"),
]
remaining = mask
for flag, label in checks:
if (remaining & flag) == flag:
parts.append(label)
remaining &= ~flag
break # one composite label is enough; remaining bits shown as hex
if remaining:
parts.append(hex(remaining))
return "|".join(parts) if parts else hex(mask)
else:
# ctypes mode: interpret generic rights bits
if mask & 0x10000000:
return "FULL"
parts = []
if mask & 0x80000000:
parts.append("READ")
if mask & 0x40000000:
parts.append("WRITE")
if mask & 0x20000000:
parts.append("EXECUTE")
if mask & 0x001F01FF:
parts.append("FULL(specific)")
return "|".join(parts) if parts else hex(mask)
def list_permissions_pywin32(path: str) -> None:
sd = win32security.GetFileSecurity(
path,
win32security.OWNER_SECURITY_INFORMATION |
win32security.DACL_SECURITY_INFORMATION,
)
owner_sid = sd.GetSecurityDescriptorOwner()
owner_name, owner_domain, _ = win32security.LookupAccountSid(None, owner_sid)
print(f"\n Path : {path}")
print(f" Owner : {owner_domain}\\{owner_name}")
dacl = sd.GetSecurityDescriptorDacl()
if dacl is None:
print(" DACL : (none / full access to everyone)")
return
print(f" ACEs : {dacl.GetAceCount()}")
print(f" {'Account':<40} {'Type':<8} {'Permissions'}")
print(f" {'-'*40} {'-'*8} {'-'*30}")
for i in range(dacl.GetAceCount()):
ace = dacl.GetAce(i)
ace_type = ace[0][0]
ace_mask = ace[1]
ace_sid = ace[2]
try:
name, domain, _ = win32security.LookupAccountSid(None, ace_sid)
account = f"{domain}\\{name}"
except Exception:
account = str(ace_sid)
type_str = "ALLOW" if ace_type == win32con.ACCESS_ALLOWED_ACE_TYPE else "DENY"
print(f" {account:<40} {type_str:<8} {_ace_mask_to_str(ace_mask)}")
def list_permissions_ctypes(path: str) -> None:
"""
Minimal ACL listing via ctypes.
Falls back to os.stat for basic permission bits when full DACL
enumeration is not available without pywin32.
"""
print(f"\n Path : {path}")
print(" [ctypes mode: basic stat permissions shown]")
s = os.stat(path)
mode = s.st_mode
print(f" Mode : {stat.filemode(mode)} ({oct(mode)})")
print(" Note : Install pywin32 for full ACL/ACE listing.")
def list_permissions(path: str) -> None:
if BACKEND == "pywin32":
list_permissions_pywin32(path)
else:
list_permissions_ctypes(path)
# ---------------------------------------------------------------------------
# ACL modify
# ---------------------------------------------------------------------------
def _resolve_account(account: str | None) -> str:
"""Return account name; if None, return current user."""
if account:
return account
if BACKEND == "pywin32":
return win32api.GetUserNameEx(win32con.NameSamCompatible)
buf = ctypes.create_unicode_buffer(256)
size = ctypes.c_ulong(256)
ctypes.windll.advapi32.GetUserNameW(buf, ctypes.byref(size))
domain_buf = ctypes.create_unicode_buffer(256)
domain_size = ctypes.c_ulong(256)
ctypes.windll.advapi32.GetComputerNameW(domain_buf, ctypes.byref(domain_size))
return f"{domain_buf.value}\\{buf.value}"
def modify_permissions_pywin32(
path: str,
account: str | None,
allow: bool,
mask: int,
) -> None:
account_name = _resolve_account(account)
sid, _, _ = win32security.LookupAccountName(None, account_name)
sd = win32security.GetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION)
dacl = sd.GetSecurityDescriptorDacl()
if dacl is None:
dacl = win32security.ACL()
if allow:
dacl.AddAccessAllowedAce(win32security.ACL_REVISION, mask, sid)
else:
dacl.AddAccessDeniedAce(win32security.ACL_REVISION, mask, sid)
sd.SetSecurityDescriptorDacl(True, dacl, False)
win32security.SetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION, sd)
action = "ALLOW" if allow else "DENY"
print(f" [OK] {action} {_ace_mask_to_str(mask)} -> {account_name} on {path}")
def modify_permissions(
path: str,
account: str | None,
allow: bool,
mask: int,
) -> None:
if BACKEND == "pywin32":
modify_permissions_pywin32(path, account, allow, mask)
else:
print(" [WARN] pywin32 not available. Using os.chmod (basic POSIX bits only).")
current = stat.S_IMODE(os.stat(path).st_mode)
if allow:
os.chmod(path, current | stat.S_IRUSR | stat.S_IWUSR)
else:
os.chmod(path, current & ~stat.S_IWRITE)
print(f" [OK] chmod applied to {path}")
# ---------------------------------------------------------------------------
# ACL reset (restore inheritance)
# ---------------------------------------------------------------------------
def reset_permissions_pywin32(path: str) -> None:
"""Remove explicit ACEs and restore DACL inheritance from parent."""
sd = win32security.GetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION)
empty_dacl = win32security.ACL()
sd.SetSecurityDescriptorDacl(True, empty_dacl, False)
# SE_DACL_PROTECTED = 0x1000 — clear it to allow inheritance
sd.SetSecurityDescriptorControl(
win32security.SE_DACL_PROTECTED, 0
)
win32security.SetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION, sd)
print(f" [OK] DACL reset (inheritance restored) on {path}")
def reset_permissions_ctypes(path: str) -> None:
print(" [WARN] pywin32 not available. Applying full read/write via os.chmod.")
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
print(f" [OK] Permissions reset (basic) on {path}")
def reset_permissions(path: str) -> None:
if BACKEND == "pywin32":
reset_permissions_pywin32(path)
else:
reset_permissions_ctypes(path)
# ---------------------------------------------------------------------------
# Lock (deny all access for Everyone)
# ---------------------------------------------------------------------------
def lock_path_pywin32(path: str) -> None:
everyone_sid = win32security.CreateWellKnownSid(
win32security.WinWorldSid, None
)
sd = win32security.GetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION)
dacl = win32security.ACL()
dacl.AddAccessDeniedAce(
win32security.ACL_REVISION,
nsc.FILE_ALL_ACCESS,
everyone_sid,
)
sd.SetSecurityDescriptorDacl(True, dacl, False)
win32security.SetFileSecurity(path, win32security.DACL_SECURITY_INFORMATION, sd)
print(f" [OK] Locked (DENY ALL for Everyone) -> {path}")
def lock_path_ctypes(path: str) -> None:
print(" [WARN] pywin32 not available. Removing write bits via os.chmod.")
os.chmod(path, stat.S_IREAD)
print(f" [OK] Write access removed on {path}")
def lock_path(path: str) -> None:
if BACKEND == "pywin32":
lock_path_pywin32(path)
else:
lock_path_ctypes(path)
# ---------------------------------------------------------------------------
# Force delete
# ---------------------------------------------------------------------------
def _on_rm_error(func, path, exc_info):
"""onerror handler: strip read-only flag then retry."""
os.chmod(path, stat.S_IWRITE)
func(path)
def force_delete(path: str) -> None:
"""Force-delete a file or directory tree, taking ownership first."""
enable_privilege("SeRestorePrivilege")
enable_privilege("SeTakeOwnershipPrivilege")
target = Path(path)
if not target.exists():
print(f" [WARN] Path does not exist: {path}")
return
# Take ownership of all items
if BACKEND == "pywin32":
_take_ownership_recursive(path)
if target.is_file() or target.is_symlink():
try:
os.chmod(path, stat.S_IWRITE)
os.remove(path)
print(f" [OK] Deleted file: {path}")
except Exception as exc:
print(f" [FAIL] {exc}")
else:
try:
shutil.rmtree(path, onerror=_on_rm_error)
print(f" [OK] Deleted directory tree: {path}")
except Exception as exc:
print(f" [FAIL] {exc}")
def _take_ownership_recursive(path: str) -> None:
"""Take ownership of path (and all children if directory)."""
try:
_take_ownership_single(path)
except Exception:
pass
if os.path.isdir(path):
for root, dirs, files in os.walk(path):
for name in dirs + files:
try:
_take_ownership_single(os.path.join(root, name))
except Exception:
pass
def _take_ownership_single(path: str) -> None:
token = win32security.OpenProcessToken(
win32api.GetCurrentProcess(),
win32con.TOKEN_QUERY,
)
owner_sid = win32security.GetTokenInformation(
token, win32security.TokenUser
)[0]
sd = win32security.SECURITY_DESCRIPTOR()
sd.SetSecurityDescriptorOwner(owner_sid, False)
win32security.SetFileSecurity(
path, win32security.OWNER_SECURITY_INFORMATION, sd
)
# ---------------------------------------------------------------------------
# Recursive walker
# ---------------------------------------------------------------------------
def _walk(path: str, recursive: bool, action, **kwargs):
"""Apply action to path, and optionally all children."""
action(path, **kwargs)
if recursive and os.path.isdir(path):
for root, dirs, files in os.walk(path):
for name in dirs + files:
child = os.path.join(root, name)
try:
action(child, **kwargs)
except Exception as exc:
print(f" [SKIP] {child}: {exc}")
# ---------------------------------------------------------------------------
# Mask presets
# ---------------------------------------------------------------------------
def _mask_from_preset(preset: str) -> int:
if BACKEND == "pywin32":
presets = {
"read": nsc.FILE_GENERIC_READ,
"write": nsc.FILE_GENERIC_WRITE,
"execute": nsc.FILE_GENERIC_EXECUTE,
"full": nsc.FILE_ALL_ACCESS,
}
else:
presets = {
"read": 0x80000000, # GENERIC_READ
"write": 0x40000000, # GENERIC_WRITE
"execute": 0x20000000, # GENERIC_EXECUTE
"full": 0x10000000, # GENERIC_ALL
}
return presets.get(preset.lower(), nsc.FILE_ALL_ACCESS if BACKEND == "pywin32" else 0x10000000)
# ---------------------------------------------------------------------------
# Interactive menu
# ---------------------------------------------------------------------------
def _prompt_path() -> str:
while True:
p = input("\n Target path: ").strip().strip('"')
if os.path.exists(p):
return p
print(" [ERR] Path not found. Try again.")
def _prompt_recursive() -> bool:
ans = input(" Recursive? (y/N): ").strip().lower()
return ans == "y"
def interactive_menu() -> None:
print("\n" + "=" * 58)
print(" Windows ACL Manager")
print(f" Backend : {BACKEND}")
print(f" Admin : {'Yes' if _is_admin() else 'No (some ops may fail)'}")
print("=" * 58)
menu = [
("List permissions", "list"),
("Modify permissions", "modify"),
("Reset permissions", "reset"),
("Lock (deny all)", "lock"),
("Force delete", "delete"),
("Exit", "exit"),
]
while True:
print()
for i, (label, _) in enumerate(menu, 1):
print(f" [{i}] {label}")
choice = input("\n Select: ").strip()
if not choice.isdigit() or not (1 <= int(choice) <= len(menu)):
print(" [ERR] Invalid selection.")
continue
_, action = menu[int(choice) - 1]
if action == "exit":
break
path = _prompt_path()
recursive = _prompt_recursive() if action != "delete" else False
if action == "list":
if recursive and os.path.isdir(path):
for root, dirs, files in os.walk(path):
list_permissions(root)
for f in files:
list_permissions(os.path.join(root, f))
else:
list_permissions(path)
elif action == "modify":
account = input(" Account (leave blank for current user): ").strip() or None
preset = input(" Permission [read/write/execute/full]: ").strip() or "full"
allow_str = input(" Allow or Deny? (A/d): ").strip().lower()
allow = allow_str != "d"
mask = _mask_from_preset(preset)
_walk(path, recursive, lambda p, **_: modify_permissions(p, account, allow, mask))
elif action == "reset":
_walk(path, recursive, lambda p, **_: reset_permissions(p))
elif action == "lock":
_walk(path, recursive, lambda p, **_: lock_path(p))
elif action == "delete":
confirm = input(f" CONFIRM delete '{path}'? (yes/NO): ").strip()
if confirm.lower() == "yes":
force_delete(path)
else:
print(" Cancelled.")
# ---------------------------------------------------------------------------
# CLI
# ---------------------------------------------------------------------------
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
prog="win_acl_manager",
description="Windows ACL Manager — list/modify/reset/lock/delete",
)
sub = parser.add_subparsers(dest="command")
# list
p_list = sub.add_parser("list", help="List ACL permissions")
p_list.add_argument("path")
p_list.add_argument("-r", "--recursive", action="store_true")
# modify
p_mod = sub.add_parser("modify", help="Add ACE to DACL")
p_mod.add_argument("path")
p_mod.add_argument("-u", "--account", default=None, help="Account name (default: current user)")
p_mod.add_argument("-p", "--perm", default="full", choices=["read", "write", "execute", "full"])
p_mod.add_argument("-d", "--deny", action="store_true", help="Deny instead of allow")
p_mod.add_argument("-r", "--recursive", action="store_true")
# reset
p_reset = sub.add_parser("reset", help="Restore inheritance / reset DACL")
p_reset.add_argument("path")
p_reset.add_argument("-r", "--recursive", action="store_true")
# lock
p_lock = sub.add_parser("lock", help="Deny all access (Everyone)")
p_lock.add_argument("path")
p_lock.add_argument("-r", "--recursive", action="store_true")
# delete
p_del = sub.add_parser("delete", help="Force delete (takes ownership first)")
p_del.add_argument("path")
p_del.add_argument("--confirm", action="store_true", help="Skip confirmation prompt")
return parser
def run_cli(args) -> None:
if args.command == "list":
if args.recursive and os.path.isdir(args.path):
for root, dirs, files in os.walk(args.path):
list_permissions(root)
for f in files:
list_permissions(os.path.join(root, f))
else:
list_permissions(args.path)
elif args.command == "modify":
mask = _mask_from_preset(args.perm)
_walk(
args.path, args.recursive,
lambda p, **_: modify_permissions(p, args.account, not args.deny, mask),
)
elif args.command == "reset":
_walk(args.path, args.recursive, lambda p, **_: reset_permissions(p))
elif args.command == "lock":
_walk(args.path, args.recursive, lambda p, **_: lock_path(p))
elif args.command == "delete":
if not args.confirm:
ans = input(f" CONFIRM delete '{args.path}'? (yes/NO): ").strip()
if ans.lower() != "yes":
print(" Cancelled.")
return
force_delete(args.path)
# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------
def main() -> None:
if not sys.platform.startswith("win"):
print("[ERR] This script is designed for Windows only.")
sys.exit(1)
if not _is_admin():
print("[WARN] Not running as Administrator. Some operations may fail.")
enable_privilege("SeRestorePrivilege")
enable_privilege("SeTakeOwnershipPrivilege")
enable_privilege("SeSecurityPrivilege")
parser = build_parser()
args = parser.parse_args()
if args.command:
run_cli(args)
else:
interactive_menu()
input("\nPress ENTER to exit.")
if __name__ == "__main__":
main()
NOT :
Şuradan esinlenildi....
https://windowsforum.com/threads/python ... ns.338678/
Ayrıca yukarıda verilen site, yapay zeka tarafından yönetiliyor.Belki de bu forumlar'da ilk olabilir.

