qubes-core-admin-linux/dom0-updates/qubes-receive-updates
Marek Marczykowski-Górecki 8689170368
dom0-updates: move PackageKit cache refresh to GUI handling
PackageKit is used only by GUI updaters, refresh its cache only then.
Since PackageKit daemon do not read dnf.conf, it doesn't know  the right
repository location, so try to access network, which results in
timeouts. But at the same time, it invalidate previous cache, which is
what we need.
Do not delay every qubes-dom0-update call by pkcon call.
2018-01-08 01:40:18 +01:00

132 lines
4.6 KiB
Python
Executable File

#!/usr/bin/python3
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
import os
import os.path
import re
import sys
import subprocess
import shutil
import grp
import qubesadmin
updates_dir = "/var/lib/qubes/updates"
updates_rpm_dir = updates_dir + "/rpm"
updates_repodata_dir = updates_dir + "/repodata"
updates_error_file = updates_dir + "/errors"
updates_error_file_handle = None
comps_file = None
if os.path.exists('/usr/share/qubes/Qubes-comps.xml'):
comps_file = '/usr/share/qubes/Qubes-comps.xml'
package_regex = re.compile(r"^[A-Za-z0-9._+-]{1,128}.rpm$")
# example valid outputs:
# .....rpm: rsa sha1 (md5) pgp md5 OK
# .....rpm: (sha1) dsa sha1 md5 gpg OK
# example INVALID outputs:
# .....rpm: sha1 md5 OK
# .....rpm: RSA sha1 ((MD5) PGP) md5 NOT OK (MISSING KEYS: (MD5) PGP#246110c1)
gpg_ok_regex = re.compile(r": [a-z0-9() ]* (pgp|gpg) [a-z0-9 ]*OK$")
def dom0updates_fatal(pkg, msg):
global updates_error_file_handle
print(msg, file=sys.stderr)
if updates_error_file_handle is None:
updates_error_file_handle = open(updates_error_file, "a")
updates_error_file_handle.write(msg + "\n")
os.remove(pkg)
def handle_dom0updates(updatevm):
global updates_error_file_handle
source = os.getenv("QREXEC_REMOTE_DOMAIN")
if source != updatevm.name:
print('Domain ' + str(source) + ' not allowed to send dom0 updates',
file=sys.stderr)
exit(1)
# Clean old packages
if os.path.exists(updates_rpm_dir):
shutil.rmtree(updates_rpm_dir)
if os.path.exists(updates_repodata_dir):
shutil.rmtree(updates_repodata_dir)
if os.path.exists(updates_error_file):
os.remove(updates_error_file)
os.environ['LC_ALL'] = 'C'
qubes_gid = grp.getgrnam('qubes').gr_gid
old_umask = os.umask(0o002)
os.mkdir(updates_rpm_dir)
os.chown(updates_rpm_dir, -1, qubes_gid)
os.chmod(updates_rpm_dir, 0o0775)
subprocess.check_call(["/usr/libexec/qubes/qfile-dom0-unpacker",
str(os.getuid()), updates_rpm_dir])
# Verify received files
for untrusted_f in os.listdir(updates_rpm_dir):
if not package_regex.match(untrusted_f):
dom0updates_fatal(updates_rpm_dir + '/' + untrusted_f,
'Domain ' + source + ' sent unexpected file: ' + untrusted_f)
else:
f = untrusted_f
assert '/' not in f
assert '\0' not in f
assert '\x1b' not in f
full_path = updates_rpm_dir + "/" + f
if os.path.islink(full_path) or not os.path.isfile(full_path):
dom0updates_fatal(
full_path, 'Domain ' + source + ' sent not regular file')
p = subprocess.Popen(["/bin/rpm", "-K", full_path],
stdout=subprocess.PIPE)
output = p.communicate()[0].decode('ascii')
if p.returncode != 0:
dom0updates_fatal(full_path,
'Error while verifing %s signature: %s' % (f, output))
if not gpg_ok_regex.search(output.strip()):
dom0updates_fatal(full_path,
'Domain ' + source + ' sent not signed rpm: ' + f)
if updates_error_file_handle is not None:
updates_error_file_handle.close()
# After updates received - create repo metadata
createrepo_cmd = ["/usr/bin/createrepo_c"]
if comps_file:
createrepo_cmd += ["-g", comps_file]
createrepo_cmd += ["-q", updates_dir]
subprocess.check_call(createrepo_cmd)
os.chown(updates_repodata_dir, -1, qubes_gid)
os.chmod(updates_repodata_dir, 0o0775)
# Clean old cache
subprocess.call(["sudo", "/usr/bin/yum", "-q", "clean", "all"],
stdout=sys.stderr)
os.umask(old_umask)
exit(0)
def main():
app = qubesadmin.Qubes()
updatevm = app.updatevm
if updatevm is None:
exit(1)
handle_dom0updates(updatevm)
main()