diff --git a/setup/__init__.py b/setup/__init__.py index 0ddb5931c3..560b7084f8 100644 --- a/setup/__init__.py +++ b/setup/__init__.py @@ -176,6 +176,7 @@ class Command: SRC = SRC RESOURCES = os.path.join(os.path.dirname(SRC), 'resources') description = '' + drop_privileges_for_subcommands = False sub_commands = [] @@ -202,15 +203,6 @@ class Command: if self.real_uid is not None: os.seteuid(int(self.real_uid)) - def regain_privileges(self): - if not islinux or ismacos or isfreebsd: - return - if os.geteuid() != 0 and self.orig_euid == 0: - self.info('Trying to get root privileges') - os.seteuid(0) - if os.getegid() != 0: - os.setegid(0) - def pre_sub_commands(self, opts): pass @@ -225,8 +217,26 @@ class Command: def run_cmd(self, cmd, opts): from setup.commands import command_names cmd.pre_sub_commands(opts) - for scmd in cmd.sub_commands: - self.run_cmd(scmd, opts) + if self.drop_privileges_for_subcommands and self.orig_euid is not None and os.getuid() == 0 and self.real_uid is not None: + if self.real_user is not None: + self.info('Dropping privileges to those of', self.real_user+':', self.real_uid) + + pid = os.fork() + if pid == 0: + if self.real_gid is not None: + os.setgid(int(self.real_gid)) + if self.real_uid is not None: + os.setuid(int(self.real_uid)) + for scmd in cmd.sub_commands: + self.run_cmd(scmd, opts) + raise SystemExit(0) + else: + rpid, st = os.waitpid(pid, 0) + if code := os.waitstatus_to_exitcode(st) != 0: + sys.exit(code) + else: + for scmd in cmd.sub_commands: + self.run_cmd(scmd, opts) st = time.time() self.running(cmd) diff --git a/setup/build_environment.py b/setup/build_environment.py index 553c41c2e8..78640e8771 100644 --- a/setup/build_environment.py +++ b/setup/build_environment.py @@ -109,10 +109,13 @@ def consolidate(envvar, default): return [x for x in ans if x and os.path.exists(x)] -qraw = subprocess.check_output([QMAKE, '-query']).decode('utf-8') +qraw = None def readvar(name): + global qraw + if qraw is None: + qraw = subprocess.check_output([QMAKE, '-query']).decode('utf-8') return re.search(f'^{name}:(.+)$', qraw, flags=re.M).group(1).strip() diff --git a/setup/install.py b/setup/install.py index e9e14f9184..5717ad1d86 100644 --- a/setup/install.py +++ b/setup/install.py @@ -60,6 +60,7 @@ class Develop(Command): ''') short_description = 'Setup a development environment for calibre' MODE = 0o755 + drop_privileges_for_subcommands = True sub_commands = ['build', 'resources', 'iso639', 'iso3166', 'gui',] @@ -128,13 +129,6 @@ class Develop(Command): 'supported on linux. On other platforms, see the User Manual' ' for help with setting up a development environment.') raise SystemExit(1) - - if os.geteuid() == 0: - # We drop privileges for security, regaining them when installing - # files. Also ensures that any config files created as a side - # effect of the build process are not owned by root. - self.drop_privileges() - # Ensure any config files created as a side effect of importing calibre # during the build process are in /tmp os.environ['CALIBRE_CONFIG_DIRECTORY'] = os.environ.get('CALIBRE_CONFIG_DIRECTORY', '/tmp/calibre-install-config') @@ -142,7 +136,6 @@ class Develop(Command): def run(self, opts): self.manifest = [] self.opts = opts - self.regain_privileges() self.consolidate_paths() self.install_files() self.write_templates()