"""Fixperms class for CWP"""
from stat import S_ISLNK, S_ISREG, S_ISDIR
from fixperms_base import PermMap
from fixperms_ids import IDCache
from fixperms_cli import Args
class CwpPermMap(PermMap):
"""Fixperms class for CWP"""
def __init__(self, ids: IDCache, args: Args, user: str):
all_docroots=list(cwp.get_docroots(user).values()),
docroot_chown=(user, 'nobody'),
# pylint: disable=duplicate-code
# Order these rules more specific to less specific regex.
uid, gid = self.uid, self.gid
# sensitive passwords: ~/.pgpass, ~/.my.cnf
self.add_rule(r"\/\.(?:pgpass|my\.cnf)$", (0o600, None), (uid, gid))
# ~/.imh directory and contents
self.add_rule(r"\/\.imh(?:$|\/)", (0o644, 0o755), (0, 0))
# ~/.ssh directory and contents
self.add_rule(r"\/\.ssh(?:$|\/)", (0o600, 0o700), (uid, gid))
self.add_rule(r"\/\.pki(?:$|\/)", (None, 0o740), (uid, gid))
self.add_rule(r"\/.*\.(?:pl|cgi)$", (0o755, None), (uid, gid))
self.add_rule("$", (None, 0o711), (uid, gid))
# restrict access to sensitive CMS config files
r"\/.+\/(?:(?:wp-config|conf|[cC]onfig|[cC]onfiguration|"
r"LocalSettings|settings)(?:\.inc)?\.php|"
r"local\.xml|mt-config\.cgi)$",
self.add_rule(r"\/cwp_stats\/.+\.html", (0o644, None), (0, 0))
# cwp user dashboard session dir
self.add_rule(r"\/tmp\/session$", (None, 0o751), (uid, gid))
# cwp user dashboard session files
self.add_rule(r"\/tmp\/session\/sess_.+", (0o600, None), (uid, gid))
self.add_rule(r"\/\.conf$", (None, 0o755), (uid, gid))
# cwp user config dir items
self.add_rule(r"/\.conf/\..+\.sqlite$", (0o644, None), (0, 0))
r"/.conf/(?:cache|reseller)(?:\/.+\.json)?$", (0o644, 0o755), (0, 0)
self.add_rule(r"\/.softaculous(?:$|\/)", (0o600, 0o711), (uid, gid))
# contents of homedir which do not match a previous regex
self.add_rule(r"\/", (0o644, 0o755), (uid, gid))
def fixperms(self) -> None:
if not self.args.skip_mail:
"""Iterate all paths in the user's mail dirs"""
for top_dir in cwp.vmail_paths(self.user, check_exists=True):
yield from self.walk(str(top_dir))
"""Fix permissions of a CWP user's mail dirs"""
gid = self.ids.getgrnam('mail').gr_gid
for stat, path in self.iter_vmail():
if S_ISLNK(stat.st_mode):
self.log.warning("Skipping unexpected symlink at %s", path)
if S_ISDIR(stat.st_mode): # directory
elif S_ISREG(stat.st_mode): # regular file
if os.path.basename(path).startswith('dovecot-uidvalidity.'):
if self.uid != stat.st_uid and stat.st_nlink > 1:
self.hard_links.add(path, stat, (uid, gid), mode)
self.log.warning("Skipping unexpected path type at %s", path)
self.lchown(path, stat, uid, gid)
self.lchmod(path, stat, mode)