Skip to content

Commit

Permalink
Merge !1616: datamodel: types: files: improvements and fixes
Browse files Browse the repository at this point in the history
Fixes #919
  • Loading branch information
vcunat committed Oct 7, 2024
2 parents eed008a + e28a720 commit 64f66e5
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 10 deletions.
10 changes: 9 additions & 1 deletion python/knot_resolver/datamodel/globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,14 @@
class Context:
resolve_root: Optional[Path]
strict_validation: bool
permissions_default: bool

def __init__(self, resolve_root: Optional[Path], strict_validation: bool = True) -> None:
def __init__(
self, resolve_root: Optional[Path], strict_validation: bool = True, permissions_default: bool = True
) -> None:
self.resolve_root = resolve_root
self.strict_validation = strict_validation
self.permissions_default = permissions_default


_global_context: Context = Context(None)
Expand Down Expand Up @@ -59,3 +63,7 @@ def get_resolve_root() -> Path:

def get_strict_validation() -> bool:
return _global_context.strict_validation


def get_permissions_default() -> bool:
return _global_context.permissions_default
18 changes: 12 additions & 6 deletions python/knot_resolver/datamodel/types/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
from enum import Flag, auto
from grp import getgrnam
from pathlib import Path
from pwd import getpwnam
from pwd import getpwnam, getpwuid
from typing import Any, Dict, Tuple, Type, TypeVar

from knot_resolver.constants import GROUP, USER
from knot_resolver.datamodel.globals import get_resolve_root, get_strict_validation
from knot_resolver.datamodel.globals import get_permissions_default, get_resolve_root, get_strict_validation
from knot_resolver.utils.modeling.base_value_type import BaseValueType


Expand Down Expand Up @@ -157,8 +157,14 @@ def _kres_accessible(dest_path: Path, perm_mode: _PermissionMode) -> bool:
_PermissionMode.EXECUTE: [stat.S_IXUSR, stat.S_IXGRP, stat.S_IXOTH],
}

user_uid = getpwnam(USER).pw_uid
user_gid = getgrnam(GROUP).gr_gid
if get_permissions_default():
user_uid = getpwnam(USER).pw_uid
user_gid = getgrnam(GROUP).gr_gid
username = USER
else:
user_uid = os.getuid()
user_gid = os.getgid()
username = getpwuid(user_uid).pw_name

dest_stat = os.stat(dest_path)
dest_uid = dest_stat.st_uid
Expand All @@ -168,13 +174,13 @@ def _kres_accessible(dest_path: Path, perm_mode: _PermissionMode) -> bool:
def accessible(perm: _PermissionMode) -> bool:
if user_uid == dest_uid:
return bool(dest_mode & chflags[perm][0])
b_groups = os.getgrouplist(os.getlogin(), user_gid)
b_groups = os.getgrouplist(username, user_gid)
if user_gid == dest_gid or dest_gid in b_groups:
return bool(dest_mode & chflags[perm][1])
return bool(dest_mode & chflags[perm][2])

# __iter__ for class enum.Flag added in python3.11
# 'for perm in perm_mode:' failes for <=python3.11
# 'for perm in perm_mode:' fails for <=python3.11
for perm in _PermissionMode:
if perm in perm_mode:
if not accessible(perm):
Expand Down
17 changes: 14 additions & 3 deletions python/knot_resolver/manager/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from functools import partial
from http import HTTPStatus
from pathlib import Path
from pwd import getpwuid
from time import time
from typing import Any, Dict, List, Literal, Optional, Set, Union, cast

Expand All @@ -17,7 +18,7 @@
from aiohttp.web_response import json_response
from aiohttp.web_runner import AppRunner, TCPSite, UnixSite

from knot_resolver.constants import CONFIG_FILE
from knot_resolver.constants import CONFIG_FILE, USER
from knot_resolver.controller import get_best_controller_implementation
from knot_resolver.controller.exceptions import SubprocessControllerExecException
from knot_resolver.controller.registered_workers import command_single_registered_worker
Expand Down Expand Up @@ -517,6 +518,14 @@ async def start_server(config: Path = CONFIG_FILE) -> int:
# Block signals during initialization to force their processing once everything is ready
signal.pthread_sigmask(signal.SIG_BLOCK, Server.all_handled_signals())

# Check if we are running under the intended user, if not, log a warning message
pw_username = getpwuid(os.getuid()).pw_name
if pw_username != USER:
logger.warning(
f"Knot Resolver does not run as the default '{USER}' user, but as '{pw_username}' instead."
" This may or may not affect the configuration validation and the proper functioning of the resolver."
)

# before starting server, initialize the subprocess controller, config store, etc. Any errors during inicialization
# are fatal
try:
Expand All @@ -527,8 +536,10 @@ async def start_server(config: Path = CONFIG_FILE) -> int:
config_raw = await _load_raw_config(config)

# before processing any configuration, set validation context
# - resolve_root = root against which all relative paths will be resolved
set_global_validation_context(Context(config.parent, True))
# - resolve_root: root against which all relative paths will be resolved
# - strict_validation: check for path existence during configuration validation
# - permissions_default: validate dirs/files rwx permissions against default user:group in constants
set_global_validation_context(Context(config.parent, True, False))

# We want to change cwd as soon as possible. Some parts of the codebase are using os.getcwd() to get the
# working directory.
Expand Down

0 comments on commit 64f66e5

Please sign in to comment.