Compare commits

..

21 Commits

Author SHA1 Message Date
Marek Marczykowski-Górecki
2695a6ec90
version 2.0.31 2015-10-01 11:51:42 +02:00
Marek Marczykowski-Górecki
af0fdb3cd3
rpm: move os-prober removing code to kernel-install subpackage
Main qubes-core-dom0 should not be installed as part of installer image,
but os-prober dependency pulls that in. So move it into
qubes-core-dom0-kernel-install subpackage. After all this is where grub
config regeneration code is placed, so it is more logical place.

(cherry picked from commit e062c431dd)
2015-10-01 11:51:20 +02:00
Marek Marczykowski-Górecki
1d5b55465f
Prevent installing all the qubes packages in the installer image
Split kernel-install hook into separate package, as only this part is
needed by the installer. This will prevent installing all the Qubes/Xen
staff in the installer, especially udev scripts and xenstored, which
doesn't play well with anaconda.

(cherry picked from commit 5e6d3a273d)

Conflicts:
	rpm_spec/core-dom0-linux.spec
2015-10-01 11:51:17 +02:00
Marek Marczykowski-Górecki
bc3c9fa422
Generate initramfs in kernel-install hook
The default one generates initramfs in location expected by Boot Loader
Specification, which as noted before, isn't useful for Qubes.

(cherry picked from commit fddeb4a23c)
2015-10-01 11:50:52 +02:00
Marek Marczykowski-Górecki
dab1417c24
rpm: provide qubes-core-dom0-linux-kernel-install virtual pkg
This is for kernel package dependencies, since we have the same kernel
packages for both R2 and R3.0

(cherry picked from commit f056e0341e)
2015-10-01 11:50:52 +02:00
Marek Marczykowski-Górecki
ed6ab1e598
Add kernel post-installation script to regenerate grub2 config
Since we now allow using Fedora kernel, add a script to generate proper
bootloader configuration then. Standard Fedora mechanism relies on
Boot Loader Specification support in grub2, which sadly does not support
Xen, so it is useless in Qubes.

(cherry picked from commit 2a14ae9c0b)

Conflicts:
	rpm_spec/core-dom0-linux.spec
2015-10-01 11:50:47 +02:00
Marek Marczykowski-Górecki
eccca4e59e
version 2.0.30 2015-09-29 10:50:41 +02:00
Marek Marczykowski-Górecki
740994b8d9
Disable lesspipe in dom0
It can be dangerous when processing untrusted content (for example VM
logs).
Details:
https://groups.google.com/d/msgid/qubes-users/20150527215812.GA13915%40mail-itl

(cherry picked from commit 8acd40905d)
2015-09-27 23:41:23 +02:00
Marek Marczykowski-Górecki
15451be6f8 version 2.0.29 2015-07-28 00:32:57 +02:00
Marek Marczykowski-Górecki
547854bed6 rpm: force removal os-prober package
It can be can be harmful, because it accesses (and mounts) every block
device, including VM controlled /dev/loop*.
2015-07-28 00:32:44 +02:00
Marek Marczykowski-Górecki
b96016101c version 2.0.28 2015-06-20 22:00:36 +02:00
Marek Marczykowski-Górecki
1c7fcb7de4 appmenus: allow '_' in Exec and other fields
(cherry picked from commit 07de8f7515)
2015-06-20 22:00:36 +02:00
Marek Marczykowski-Górecki
43f2865c41 dom0-update: improve package validation regexp - include DSA case (#988)
Apparently when package is signed with DSA key, rpm -K output is totally
different. This is the case for bumblebee package on rpmfusion.

Fixes qubesos/qubes-issues#988

(cherry picked from commit a5650d3251)
2015-06-20 22:00:36 +02:00
Marek Marczykowski-Górecki
3cbe2fa7e7 dom0-update: clear error marker before downloading new packages (#987)
Otherwise if some package download fails once - further tries will also
report errors.

Fixes qubesos/qubes-issues#987

(cherry picked from commit f2b5cf1cc0)
2015-06-20 22:00:35 +02:00
Marek Marczykowski-Górecki
690e10ffd4 dom0-update: prevent template package upgrades (#996)
This would override user changes to the template. Previous method
(Obsoletes: rpm header) doesn't work now, so add explicit exclude list
as yum option

Fixes qubesos/qubes-issues#996

(cherry picked from commit 4cab815317)

Conflicts:
	dom0-updates/qubes-dom0-update
2015-06-20 21:50:53 +02:00
Marek Marczykowski-Górecki
d276a1590c gitignore
(cherry picked from commit ed363452c9)
2015-05-16 23:17:30 +02:00
Marek Marczykowski-Górecki
d018452cd8 version 2.0.27 2015-02-10 06:47:33 +01:00
Marek Marczykowski-Górecki
49c1fe9004 Add "--" to separate options from (untrusted) non-options arguments
This will prevent passing an option instead of command (qvm-run) /
domain name (qrexec-policy). In both cases when VM tries to pass some
option it would fail because missing argument then - VM can not pass
additional arguments, so if one act as an option, one argument will be
missing).

(cherry picked from commit d031126737)

Conflicts:
	qrexec/qrexec-daemon.c
2015-02-10 02:39:06 +01:00
Marek Marczykowski-Górecki
423bd89069 version 2.0.26 2015-01-30 23:38:33 +01:00
Marek Marczykowski-Górecki
4b27e24ac9 appmenus: call kbuildsycoca4 only once after template update (#886) 2015-01-26 03:59:22 +01:00
Marek Marczykowski-Górecki
ab708e0b6b version 2.0.25 2014-11-18 17:24:33 +01:00
99 changed files with 2631 additions and 934 deletions

View File

@ -1,13 +0,0 @@
sudo: required
dist: bionic
language: generic
install: git clone https://github.com/QubesOS/qubes-builder ~/qubes-builder
script: ~/qubes-builder/scripts/travis-build
env:
- DIST_DOM0=fc31 USE_QUBES_REPO_VERSION=4.1 USE_QUBES_REPO_TESTING=1
# don't build tags which are meant for code signing only
branches:
except:
- /.*_.*/
- build

View File

@ -1,4 +1,5 @@
This package contains Linux dom0 files.
This package contains Linux dom0 files, which aren't exactly part of "Qubes
core" i.e. aren't required for normal Qubes usage.
Mostly there are config files for different system services, but also some
"addons" to Qubes core:

View File

@ -0,0 +1,8 @@
[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
Name=Command Prompt
Comment=Use the command line
Categories=GNOME;GTK;Utility;TerminalEmulator;System;
Exec=cmd /c start cmd

View File

@ -0,0 +1,8 @@
[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
Name=Explorer
Comment=Browse files
Categories=Utility;Core;
Exec=explorer

View File

@ -0,0 +1,8 @@
[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
Name=Internet Explorer
Comment=Browse the Web
Categories=Network;WebBrowser;
Exec=C:\\Program Files\\Internet Explorer\\iexplore.exe

View File

@ -0,0 +1,10 @@
[Desktop Entry]
Version=1.0
Type=Application
Exec=qubes-vm-settings %VMNAME% applications
Icon=qubes-logo
Terminal=false
Name=%VMNAME%: Add more shortcuts...
GenericName=%VMNAME%: Add more shortcuts...
StartupNotify=false
Categories=System;

View File

@ -0,0 +1,10 @@
[Desktop Entry]
Version=1.0
Type=Application
Exec=sh -c 'echo firefox | /usr/lib/qubes/qfile-daemon-dvm qubes.VMShell dom0 DEFAULT red'
Icon=dispvm-red
Terminal=false
Name=DispVM: Firefox web browser
GenericName=DispVM: Web browser
StartupNotify=false
Categories=Network;

View File

@ -0,0 +1,5 @@
[Desktop Entry]
Encoding=UTF-8
Type=Directory
Name=DisposableVM
Icon=dispvm-red

View File

@ -0,0 +1,5 @@
[Desktop Entry]
Encoding=UTF-8
Type=Directory
Name=ServiceVM: %VMNAME%
Icon=%XDGICON%

View File

@ -0,0 +1,10 @@
[Desktop Entry]
Version=1.0
Type=Application
Exec=qvm-start --quiet --tray %VMNAME%
Icon=%XDGICON%
Terminal=false
Name=%VMNAME%: Start
GenericName=%VMNAME%: Start
StartupNotify=false
Categories=System;

View File

@ -0,0 +1,5 @@
[Desktop Entry]
Encoding=UTF-8
Type=Directory
Name=Template: %VMNAME%
Icon=qubes-logo

View File

@ -0,0 +1,5 @@
[Desktop Entry]
Encoding=UTF-8
Type=Directory
Name=Domain: %VMNAME%
Icon=%XDGICON%

View File

@ -0,0 +1,16 @@
#!/bin/sh
SRC=$1
DSTDIR=$2
VMNAME=$3
VMDIR=$4
XDGICON=$5
DST=$DSTDIR/$VMNAME-$(basename $SRC)
sed \
-e "s/%VMNAME%/$VMNAME/" \
-e "s %VMDIR% $VMDIR " \
-e "s/%XDGICON%/$XDGICON/" \
<$SRC >$DST

View File

@ -0,0 +1,14 @@
#!/bin/sh
SRC=$1
DST=$2
VMNAME=$3
VMDIR=$4
XDGICON=$5
sed \
-e "s/%VMNAME%/$VMNAME/" \
-e "s %VMDIR% $VMDIR " \
-e "s/%XDGICON%/$XDGICON/" \
<$SRC >$DST

View File

@ -0,0 +1,63 @@
#!/bin/sh
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2010 Joanna Rutkowska <joanna@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.
#
#
SRCDIR=$1
VMNAME=$2
VMTYPE=$3
if [ -z "$VMTYPE" ]; then
VMTYPE=appvms
fi
XDGICON=$4
VMDIR=/var/lib/qubes/$VMTYPE/$VMNAME
APPSDIR=$VMDIR/apps
if [ $# -lt 2 ]; then
echo "usage: $0 <apps_templates_dir> <vmname> [appvms|vm-templates|servicevms]"
exit
fi
mkdir -p $APPSDIR
if [ "$SRCDIR" != "none" ]; then
echo "--> Converting Appmenu Templates..."
if [ -r "$VMDIR/whitelisted-appmenus.list" ]; then
cat $VMDIR/whitelisted-appmenus.list | xargs -I{} /usr/libexec/qubes-appmenus/convert-apptemplate2vm.sh $SRCDIR/{} $APPSDIR $VMNAME $VMDIR $XDGICON
else
find $SRCDIR -name "*.desktop" $CHECK_WHITELISTED -exec /usr/libexec/qubes-appmenus/convert-apptemplate2vm.sh {} $APPSDIR $VMNAME $VMDIR $XDGICON \;
fi
/usr/libexec/qubes-appmenus/convert-apptemplate2vm.sh /usr/share/qubes-appmenus/qubes-appmenu-select.desktop $APPSDIR $VMNAME $VMDIR $XDGICON
if [ "$VMTYPE" = "vm-templates" ]; then
DIR_TEMPLATE=/usr/share/qubes-appmenus/qubes-templatevm.directory.template
elif [ "$VMTYPE" = "servicevms" ]; then
DIR_TEMPLATE=/usr/share/qubes-appmenus/qubes-servicevm.directory.template
else
DIR_TEMPLATE=/usr/share/qubes-appmenus/qubes-vm.directory.template
fi
/usr/libexec/qubes-appmenus/convert-dirtemplate2vm.sh $DIR_TEMPLATE $APPSDIR/$VMNAME-vm.directory $VMNAME $VMDIR $XDGICON
fi
echo "--> Adding Apps to the Menu..."
LC_COLLATE=C xdg-desktop-menu install $APPSDIR/*.directory $APPSDIR/*.desktop
if [ -n "$KDE_SESSION_UID" -a -z "$SKIP_CACHE_REBUILD" ]; then
kbuildsycoca4
fi

View File

@ -0,0 +1,276 @@
#!/usr/bin/python2
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2010 Joanna Rutkowska <joanna@invisiblethingslab.com>
# Copyright (C) 2013 Marek Marczykowski <marmarek@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 subprocess
import sys
import os
import os.path
import shutil
import dbus
from qubes.qubes import QubesVm,QubesHVm
from qubes.qubes import QubesException,QubesHost,QubesVmLabels
from qubes.qubes import vm_files,system_path,dry_run
import qubes.imgconverter
vm_files['appmenus_templates_subdir'] = 'apps.templates'
vm_files['appmenus_template_icons_subdir'] = 'apps.tempicons'
vm_files['appmenus_icons_subdir'] = 'apps.icons'
vm_files['appmenus_template_templates_subdir'] = 'apps-template.templates'
vm_files['appmenus_whitelist'] = 'whitelisted-appmenus.list'
system_path['appmenu_start_hvm_template'] = '/usr/share/qubes-appmenus/qubes-start.desktop'
system_path['appmenu_create_cmd'] = '/usr/libexec/qubes-appmenus/create-apps-for-appvm.sh'
system_path['appmenu_remove_cmd'] = '/usr/libexec/qubes-appmenus/remove-appvm-appmenus.sh'
def QubesVm_get_attrs_config(self, attrs):
attrs["appmenus_templates_dir"] = { "eval": \
'os.path.join(self.dir_path, vm_files["appmenus_templates_subdir"]) if self.updateable else ' + \
'self.template.appmenus_templates_dir if self.template is not None else None' }
attrs["appmenus_template_icons_dir"] = { "eval": \
'os.path.join(self.dir_path, vm_files["appmenus_template_icons_subdir"]) if self.updateable else ' + \
'self.template.appmenus_template_icons_dir if self.template is not None else None' }
attrs["appmenus_icons_dir"] = { "eval": \
'os.path.join(self.dir_path, vm_files["appmenus_icons_subdir"])' }
return attrs
def QubesTemplateVm_get_attrs_config(self, attrs):
attrs['appmenus_templates_dir'] = { 'eval': 'os.path.join(self.dir_path, vm_files["appmenus_templates_subdir"])' }
attrs['appmenus_template_icons_dir'] = { 'eval': 'os.path.join(self.dir_path, vm_files["appmenus_template_icons_subdir"])' }
return attrs
def QubesVm_appmenus_create(self, verbose=False, source_template = None):
if source_template is None:
source_template = self.template
if self.internal:
return
vmtype = None
if self.is_netvm():
vmtype = 'servicevms'
elif self.is_template():
vmtype = 'vm-templates'
else:
vmtype = 'appvms'
try:
msgoutput = None if verbose else open(os.devnull, 'w')
if source_template is not None:
subprocess.check_call([system_path["appmenu_create_cmd"],
source_template.appmenus_templates_dir,
self.name, vmtype, self.label.icon],
stdout=msgoutput, stderr=msgoutput)
elif self.appmenus_templates_dir is not None:
subprocess.check_call ([system_path["appmenu_create_cmd"],
self.appmenus_templates_dir, self.name,
vmtype, self.label.icon],
stdout=msgoutput, stderr=msgoutput)
else:
# Only add apps to menu
subprocess.check_call ([system_path["appmenu_create_cmd"],
"none", self.name, vmtype,
self.label.icon],
stdout=msgoutput, stderr=msgoutput)
except subprocess.CalledProcessError:
print >> sys.stderr, "Ooops, there was a problem creating appmenus for {0} VM!".format (self.name)
def QubesVm_appmenus_remove(self):
vmtype = None
if self.is_netvm():
vmtype = 'servicevms'
elif self.is_template():
vmtype = 'vm-templates'
else:
vmtype = 'appvms'
subprocess.check_call ([system_path["appmenu_remove_cmd"], self.name,
vmtype], stderr=open(os.devnull, 'w'))
def QubesVm_appicons_create(self, srcdir=None):
if srcdir is None:
srcdir = self.appmenus_template_icons_dir
if srcdir is None:
return
if not os.path.exists(srcdir):
return
whitelist = os.path.join(self.dir_path, vm_files['appmenus_whitelist'])
if os.path.exists(whitelist):
whitelist = [line.strip() for line in open(whitelist)]
else:
whitelist = None
if not os.path.exists(self.appmenus_icons_dir):
os.mkdir(self.appmenus_icons_dir)
elif not os.path.isdir(self.appmenus_icons_dir):
os.unlink(self.appmenus_icons_dir)
os.mkdir(self.appmenus_icons_dir)
for icon in os.listdir(srcdir):
desktop = os.path.splitext(icon)[0] + '.desktop'
if whitelist and desktop not in whitelist:
continue
qubes.imgconverter.tint(os.path.join(srcdir, icon),
os.path.join(self.appmenus_icons_dir, icon),
self.label.color)
def QubesVm_appicons_remove(self):
if not os.path.exists(self.appmenus_icons_dir): return
for icon in os.listdir(self.appmenus_icons_dir):
os.unlink(os.path.join(self.appmenus_icons_dir, icon))
def QubesVm_pre_rename(self, new_name):
self.appmenus_remove()
def QubesVm_post_rename(self, old_name):
old_dirpath = os.path.join(os.path.dirname(self.dir_path), old_name)
if self.appmenus_templates_dir is not None:
self.appmenus_templates_dir = self.appmenus_templates_dir.replace(old_dirpath, self.dir_path)
self.appmenus_create()
def QubesVm_create_on_disk(self, verbose, source_template):
if isinstance(self, QubesHVm) and source_template is None:
if verbose:
print >> sys.stderr, "--> Creating appmenus directory: {0}".format(self.appmenus_templates_dir)
os.mkdir (self.appmenus_templates_dir)
shutil.copy (system_path["appmenu_start_hvm_template"], self.appmenus_templates_dir)
source_whitelist_filename = 'vm-' + vm_files["appmenus_whitelist"]
if self.is_netvm():
source_whitelist_filename = 'netvm-' + vm_files["appmenus_whitelist"]
if source_template and os.path.exists(os.path.join(source_template.dir_path, source_whitelist_filename)):
if verbose:
print >> sys.stderr, "--> Creating default whitelisted apps list: {0}".\
format(self.dir_path + '/' + vm_files["whitelisted_appmenus"])
shutil.copy(os.path.join(source_template.dir_path, source_whitelist_filename),
os.path.join(self.dir_path, vm_files["whitelisted_appmenus"]))
if source_template and self.updateable:
if verbose:
print >> sys.stderr, "--> Copying the template's appmenus templates dir:\n{0} ==>\n{1}".\
format(source_template.appmenus_templates_dir, self.appmenus_templates_dir)
if os.path.isdir(source_template.appmenus_templates_dir):
shutil.copytree (source_template.appmenus_templates_dir, self.appmenus_templates_dir)
else:
os.mkdir(self.appmenus_templates_dir)
if os.path.isdir(source_template.appmenus_template_icons_dir):
shutil.copytree (source_template.appmenus_template_icons_dir, self.appmenus_template_icons_dir)
else:
os.mkdir(self.appmenus_template_icons_dir)
# Create appmenus
self.appicons_create()
self.appmenus_create(verbose=verbose)
def QubesVm_clone_disk_files(self, src_vm, verbose):
if src_vm.updateable and src_vm.appmenus_templates_dir is not None and self.appmenus_templates_dir is not None:
if verbose:
print >> sys.stderr, "--> Copying the template's appmenus templates dir:\n{0} ==>\n{1}".\
format(src_vm.appmenus_templates_dir, self.appmenus_templates_dir)
shutil.copytree (src_vm.appmenus_templates_dir, self.appmenus_templates_dir)
if src_vm.updateable and src_vm.appmenus_template_icons_dir is not None \
and self.appmenus_template_icons_dir is not None and \
os.path.isdir(src_vm.appmenus_template_icons_dir):
if verbose:
print >> sys.stderr, "--> Copying the template's appmenus " \
"template icons dir:\n{0} ==>\n{1}".\
format(src_vm.appmenus_template_icons_dir,
self.appmenus_template_icons_dir)
shutil.copytree (src_vm.appmenus_template_icons_dir,
self.appmenus_template_icons_dir)
for whitelist in (
vm_files["appmenus_whitelist"],
'vm-' + vm_files["appmenus_whitelist"],
'netvm-' + vm_files["appmenus_whitelist"]):
if os.path.exists(os.path.join(src_vm.dir_path, whitelist)):
if verbose:
print >> sys.stderr, "--> Copying whitelisted apps list: {0}".\
format(whitelist)
shutil.copy(os.path.join(src_vm.dir_path, whitelist),
os.path.join(self.dir_path, whitelist))
# Create appmenus
self.appicons_create()
self.appmenus_create(verbose=verbose)
def QubesVm_remove_from_disk(self):
self.appmenus_remove()
def QubesVm_label_setter(self, _):
self.appicons_create()
# Apparently desktop environments heavily caches the icons,
# see #751 for details
if os.environ.get("DESKTOP_SESSION", "") == "kde-plasma":
try:
os.unlink(os.path.expandvars("$HOME/.kde/cache-$HOSTNAME/icon-cache.kcache"))
except:
pass
try:
notify_object = dbus.SessionBus().get_object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
notify_object.Notify(
"Qubes", 0, self.label.icon, "Qubes",
"You will need to log off and log in again for the VM icons to update in the KDE launcher menu",
[], [], 10000,
dbus_interface="org.freedesktop.Notifications")
except:
pass
elif os.environ.get("DESKTOP_SESSION", "") == "xfce":
self.appmenus_remove()
self.appmenus_create()
def QubesVm_appmenus_recreate(self):
self.appmenus_remove()
self.appicons_remove()
self.appicons_create()
self.appmenus_create()
def QubesVm_set_attr(self, name, newvalue, oldvalue):
if name == 'internal':
if newvalue and not oldvalue:
self.appmenus_remove()
elif not newvalue and oldvalue:
self.appmenus_create()
# new methods
QubesVm.appmenus_create = QubesVm_appmenus_create
QubesVm.appmenus_remove = QubesVm_appmenus_remove
QubesVm.appmenus_recreate = QubesVm_appmenus_recreate
QubesVm.appicons_create = QubesVm_appicons_create
QubesVm.appicons_remove = QubesVm_appicons_remove
# hooks for existing methods
QubesVm.hooks_get_attrs_config.append(QubesVm_get_attrs_config)
QubesVm.hooks_pre_rename.append(QubesVm_pre_rename)
QubesVm.hooks_post_rename.append(QubesVm_post_rename)
QubesVm.hooks_create_on_disk.append(QubesVm_create_on_disk)
QubesVm.hooks_clone_disk_files.append(QubesVm_clone_disk_files)
QubesVm.hooks_remove_from_disk.append(QubesVm_remove_from_disk)
QubesVm.hooks_label_setter.append(QubesVm_label_setter)
QubesVm.hooks_set_attr.append(QubesVm_set_attr)

View File

@ -0,0 +1,338 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2011 Marek Marczykowski <marmarek@mimuw.edu.pl>
#
# 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 subprocess
import re
import os
import sys
import shutil
import pipes
from optparse import OptionParser
from qubes.qubes import QubesVmCollection,QubesException,system_path
from qubes.qubes import QubesHVm
from qubes.qubes import vm_files
import qubes.imgconverter
# fields required to be present (and verified) in retrieved desktop file
required_fields = [ "Name", "Exec" ]
#limits
appmenus_line_size = 1024
appmenus_line_count = 100000
# regexps for sanitization of retrieved values
std_re = re.compile(r"^[/a-zA-Z0-9.,&()_ -]*$")
fields_regexp = {
"Name": std_re,
"GenericName": std_re,
"Comment": std_re,
"Categories": re.compile(r"^[a-zA-Z0-9/.;:'() -]*$"),
"Exec": re.compile(r"^[a-zA-Z0-9()_%&>/{}\"'\\:.= -]*$"),
"Icon": re.compile(r"^[a-zA-Z0-9/_.-]*$"),
}
CATEGORIES_WHITELIST = set([
# Main Categories
# http://standards.freedesktop.org/menu-spec/1.1/apa.html 20140507
'AudioVideo', 'Audio', 'Video', 'Development', 'Education', 'Game',
'Graphics', 'Network', 'Office', 'Science', 'Settings', 'System',
'Utility',
# Additional Categories
# http://standards.freedesktop.org/menu-spec/1.1/apas02.html
'Building', 'Debugger', 'IDE', 'GUIDesigner', 'Profiling',
'RevisionControl', 'Translation', 'Calendar', 'ContactManagement',
'Database', 'Dictionary', 'Chart', 'Email', 'Finance', 'FlowChart', 'PDA',
'ProjectManagement', 'Presentation', 'Spreadsheet', 'WordProcessor',
'2DGraphics', 'VectorGraphics', 'RasterGraphics', '3DGraphics', 'Scanning',
'OCR', 'Photography', 'Publishing', 'Viewer', 'TextTools',
'DesktopSettings', 'HardwareSettings', 'Printing', 'PackageManager',
'Dialup', 'InstantMessaging', 'Chat', 'IRCClient', 'Feed', 'FileTransfer',
'HamRadio', 'News', 'P2P', 'RemoteAccess', 'Telephony', 'TelephonyTools',
'VideoConference', 'WebBrowser', 'WebDevelopment', 'Midi', 'Mixer',
'Sequencer', 'Tuner', 'TV', 'AudioVideoEditing', 'Player', 'Recorder',
'DiscBurning', 'ActionGame', 'AdventureGame', 'ArcadeGame', 'BoardGame',
'BlocksGame', 'CardGame', 'KidsGame', 'LogicGame', 'RolePlaying',
'Shooter', 'Simulation', 'SportsGame', 'StrategyGame', 'Art',
'Construction', 'Music', 'Languages', 'ArtificialIntelligence',
'Astronomy', 'Biology', 'Chemistry', 'ComputerScience',
'DataVisualization', 'Economy', 'Electricity', 'Geography', 'Geology',
'Geoscience', 'History', 'Humanities', 'ImageProcessing', 'Literature',
'Maps', 'Math', 'NumericalAnalysis', 'MedicalSoftware', 'Physics',
'Robotics', 'Spirituality', 'Sports', 'ParallelComputing', 'Amusement',
'Archiving', 'Compression', 'Electronics', 'Emulator', 'Engineering',
'FileTools', 'FileManager', 'TerminalEmulator', 'Filesystem', 'Monitor',
'Security', 'Accessibility', 'Calculator', 'Clock', 'TextEditor',
'Documentation', 'Adult', 'Core', 'KDE', 'GNOME', 'XFCE', 'GTK', 'Qt',
'Motif', 'Java', 'ConsoleOnly',
# Reserved Categories (not whitelisted)
# http://standards.freedesktop.org/menu-spec/1.1/apas03.html
# 'Screensaver', 'TrayIcon', 'Applet', 'Shell',
])
def sanitise_categories(untrusted_value):
untrusted_categories = (c.strip() for c in untrusted_value.split(';') if c)
categories = (c for c in untrusted_categories if c in CATEGORIES_WHITELIST)
return ';'.join(categories) + ';'
def fallback_hvm_appmenulist():
p = subprocess.Popen(["grep", "-rH", "=", "/usr/share/qubes-appmenus/hvm"],
stdout=subprocess.PIPE)
(stdout, stderr) = p.communicate()
return stdout.splitlines()
def get_appmenus(vm):
global appmenus_line_count
global appmenus_line_size
untrusted_appmenulist = []
if vm is None:
while appmenus_line_count > 0:
untrusted_line = sys.stdin.readline(appmenus_line_size)
if untrusted_line == "":
break
untrusted_appmenulist.append(untrusted_line.strip())
appmenus_line_count -= 1
if appmenus_line_count == 0:
raise QubesException("Line count limit exceeded")
else:
p = vm.run('QUBESRPC qubes.GetAppmenus dom0', passio_popen=True)
while appmenus_line_count > 0:
untrusted_line = p.stdout.readline(appmenus_line_size)
if untrusted_line == "":
break
untrusted_appmenulist.append(untrusted_line.strip())
appmenus_line_count -= 1
p.wait()
if p.returncode != 0:
if isinstance(vm, QubesHVm):
untrusted_appmenulist = fallback_hvm_appmenulist()
else:
raise QubesException("Error getting application list")
if appmenus_line_count == 0:
raise QubesException("Line count limit exceeded")
row_no = 0
appmenus = {}
line_rx = re.compile(r"([a-zA-Z0-9.()_-]+.desktop):([a-zA-Z0-9-]+(?:\[[a-zA-Z@_]+\])?)=(.*)")
ignore_rx = re.compile(r".*([a-zA-Z0-9._-]+.desktop):(#.*|\s+)$")
for untrusted_line in untrusted_appmenulist:
# Ignore blank lines and comments
if len(untrusted_line) == 0 or ignore_rx.match(untrusted_line):
continue
# use search instead of match to skip file path
untrusted_m = line_rx.search(untrusted_line)
if untrusted_m:
filename = untrusted_m.group(1)
assert '/' not in filename
assert '\0' not in filename
untrusted_key = untrusted_m.group(2)
assert '\0' not in untrusted_key
assert '\x1b' not in untrusted_key
assert '=' not in untrusted_key
untrusted_value = untrusted_m.group(3)
# TODO add key-dependent asserts
# Look only at predefined keys
if fields_regexp.has_key(untrusted_key):
if fields_regexp[untrusted_key].match(untrusted_value):
# now values are sanitized
key = untrusted_key
if key == 'Categories':
value = sanitise_categories(untrusted_value)
else:
value = untrusted_value
if not appmenus.has_key(filename):
appmenus[filename] = {}
appmenus[filename][key]=value
else:
print >>sys.stderr, "Warning: ignoring key %r of %s" % (untrusted_key, filename)
# else: ignore this key
return appmenus
def create_template(path, values):
# check if all required fields are present
for key in required_fields:
if not values.has_key(key):
print >>sys.stderr, "Warning: not creating/updating '%s' because of missing '%s' key" % (path, key)
return
desktop_file = open(path, "w")
desktop_file.write("[Desktop Entry]\n")
desktop_file.write("Version=1.0\n")
desktop_file.write("Type=Application\n")
desktop_file.write("Terminal=false\n")
desktop_file.write("X-Qubes-VmName=%VMNAME%\n")
if 'Icon' in values:
icon_file = os.path.splitext(os.path.split(path)[1])[0] + '.png'
desktop_file.write("Icon={0}\n".format(os.path.join(
'%VMDIR%', vm_files['appmenus_icons_subdir'], icon_file)))
else:
desktop_file.write("Icon=%XDGICON%\n")
for key in ["Name", "GenericName" ]:
if values.has_key(key):
desktop_file.write("{0}=%VMNAME%: {1}\n".format(key, values[key]))
for key in [ "Comment", "Categories" ]:
if values.has_key(key):
desktop_file.write("{0}={1}\n".format(key, values[key]))
desktop_file.write("Exec=qvm-run -q --tray -a %VMNAME% -- {0}\n".format(pipes.quote(values['Exec'])))
desktop_file.close()
def main():
env_vmname = os.environ.get("QREXEC_REMOTE_DOMAIN")
usage = "usage: %prog [options] <vm-name>\n"\
"Updates desktop file templates for given StandaloneVM or TemplateVM"
parser = OptionParser (usage)
parser.add_option ("-v", "--verbose", action="store_true", dest="verbose", default=False)
parser.add_option ("--force-root", action="store_true", dest="force_root", default=False,
help="Force to run, even with root privileges")
parser.add_option ("--force-rpc", action="store_true", dest="force_rpc", default=False,
help="Force to start a new RPC call, even if called from existing one")
(options, args) = parser.parse_args ()
if (len (args) != 1) and env_vmname is None:
parser.error ("You must specify at least the VM name!")
if env_vmname:
vmname=env_vmname
else:
vmname=args[0]
if os.geteuid() == 0:
if not options.force_root:
print >> sys.stderr, "*** Running this tool as root is strongly discouraged, this will lead you in permissions problems."
print >> sys.stderr, "Retry as unprivileged user."
print >> sys.stderr, "... or use --force-root to continue anyway."
exit(1)
qvm_collection = QubesVmCollection()
qvm_collection.lock_db_for_reading()
qvm_collection.load()
qvm_collection.unlock_db()
vm = qvm_collection.get_vm_by_name(vmname)
if vm is None:
print >>sys.stderr, "ERROR: A VM with the name '{0}' does not exist in the system.".format(vmname)
exit(1)
if vm.template is not None:
print >>sys.stderr, "ERROR: To sync appmenus for template based VM, do it on template instead"
exit(1)
if not vm.is_running():
print >>sys.stderr, "ERROR: Appmenus can be retrieved only from running VM - start it first"
exit(1)
new_appmenus = {}
if env_vmname is None or options.force_rpc:
new_appmenus = get_appmenus(vm)
else:
options.verbose = False
new_appmenus = get_appmenus(None)
if len(new_appmenus) == 0:
print >>sys.stderr, "ERROR: No appmenus received, terminating"
exit(1)
if not os.path.exists(vm.appmenus_templates_dir):
os.mkdir(vm.appmenus_templates_dir)
if not os.path.exists(vm.appmenus_template_icons_dir):
os.mkdir(vm.appmenus_template_icons_dir)
# Create new/update existing templates
if options.verbose:
print >> sys.stderr, "--> Got {0} appmenus, storing to disk".format(str(len(new_appmenus)))
for appmenu_file in new_appmenus.keys():
if options.verbose:
if os.path.exists(os.path.join(vm.appmenus_templates_dir, appmenu_file)):
print >> sys.stderr, "---> Updating {0}".format(appmenu_file)
else:
print >> sys.stderr, "---> Creating {0}".format(appmenu_file)
if 'Icon' in new_appmenus[appmenu_file]:
# the following line is used for time comparison
# del new_appmenus[appmenu_file]['Icon']
icondest = os.path.join(vm.appmenus_template_icons_dir,
os.path.splitext(appmenu_file)[0] + '.png')
try:
qubes.imgconverter.Image.get_xdg_icon_from_vm(vm,
new_appmenus[appmenu_file]['Icon']).save(icondest)
except Exception, e:
print >> sys.stderr, '----> Failed to get icon for {0}: {1!s}'.format(appmenu_file, e)
if os.path.exists(icondest):
print >> sys.stderr, '-----> Found old icon, using it instead'
else:
del new_appmenus[appmenu_file]['Icon']
create_template(os.path.join(vm.appmenus_templates_dir, appmenu_file),
new_appmenus[appmenu_file])
# Delete appmenus of removed applications
if options.verbose:
print >> sys.stderr, "--> Cleaning old files"
for appmenu_file in os.listdir(vm.appmenus_templates_dir):
if not appmenu_file.endswith('.desktop'):
continue
if not new_appmenus.has_key(appmenu_file):
if options.verbose:
print >> sys.stderr, "---> Removing {0}".format(appmenu_file)
os.unlink(os.path.join(vm.appmenus_templates_dir, appmenu_file))
if isinstance(vm, QubesHVm):
if not os.path.exists(os.path.join(vm.appmenus_templates_dir,
os.path.basename(system_path['appmenu_start_hvm_template']))):
shutil.copy(system_path['appmenu_start_hvm_template'], vm.appmenus_templates_dir)
if hasattr(vm, 'appvms'):
os.putenv('SKIP_CACHE_REBUILD', '1')
for child_vm in vm.appvms.values():
try:
child_vm.appmenus_recreate()
except Exception, e:
print >> sys.stderr, "---> Failed to recreate appmenus for " \
"'{0}': {1}".format(child_vm.name, str(e))
if 'KDE_SESSION_UID' in os.environ:
subprocess.call(['kbuildsycoca4'])
os.unsetenv('SKIP_CACHE_REBUILD')
main()

View File

@ -0,0 +1 @@
/usr/libexec/qubes-appmenus/qubes-receive-appmenus

View File

@ -0,0 +1,2 @@
#!/bin/sh
exec /usr/libexec/qubes-appmenus/qubes-receive-appmenus $@

View File

@ -0,0 +1,23 @@
#!/bin/sh
VMNAME=$1
VMTYPE=$2
if [ -z "$VMTYPE" ]; then
VMTYPE=appvms
fi
VMDIR=/var/lib/qubes/$VMTYPE/$VMNAME
APPSDIR=$VMDIR/apps
if [ $# -lt 1 ]; then
echo "usage: $0 <vmname> [appvms|vm-templates|servicevms]"
exit
fi
if ls $APPSDIR/*.directory $APPSDIR/*.desktop > /dev/null 2>&1; then
LC_COLLATE=C xdg-desktop-menu uninstall $APPSDIR/*.directory $APPSDIR/*.desktop
rm -f $APPSDIR/*.desktop $APPSDIR/*.directory
rm -f $HOME/.config/menus/applications-merged/user-$VMNAME-vm.menu
fi
if [ -n "$KDE_SESSION_UID" ]; then
kbuildsycoca4
fi

View File

@ -21,7 +21,7 @@ install: manpages
manpages: $(TOOLS_DOCS)
preview: $(rst)
$(PANDOC) $(rst) | groff -mandoc -Tlatin1 | less -R
pandoc -s -f rst -t man $(rst) | groff -mandoc -Tlatin1 | less -R
clean:
rm -f $(TOOLS_DOCS)

View File

@ -6,14 +6,14 @@ NAME
====
qubes-dom0-update - update software in dom0
:Date: 2012-04-13
SYNOPSIS
========
| qubes-dom0-update [--action=ACTION] [--clean] [--check-only] [--gui] [<yum opts>] [<pkg list>]
| qubes-dom0-update [--clean] [--check-only] [--gui] [<yum opts>] [<pkg list>]
OPTIONS
=======
--action=ACTION
Allows to pass a yum command, such as "install", "search", "downgrade" etc.
--clean
Clean yum cache before doing anything
--check-only

View File

@ -6,6 +6,8 @@ NAME
====
qvm-sync-appmenus - updates desktop file templates for given StandaloneVM or TemplateVM
:Date: 2012-04-11
SYNOPSIS
========
| qvm-sync-appmenus [options] <vm-name>

View File

@ -1,85 +0,0 @@
#!/bin/sh
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2015 Marek Marczykowski-Górecki
# <marmarek@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.
#
#
BEGIN_MARKER="### QUBES BEGIN ###"
END_MARKER="### QUBES END ###"
set -e
### helper functions begin ###
# set proxy in given config file
update_conf() {
local CONF_PATH="$1"
local CONF_OPTIONS="$2"
# Ensure that Qubes conf markers are present in the file
if ! grep -q "$BEGIN_MARKER" $CONF_PATH; then
if grep -q "$END_MARKER" $CONF_PATH; then
echo "ERROR: found QUBES END marker but not QUBES BEGIN in ${CONF_PATH}" >&2
echo "Fix the file by either removing both of them, or adding missing back and retry" >&2
exit 1
fi
cp $CONF_PATH ${CONF_PATH}.qubes-orig
echo "$BEGIN_MARKER" >> $CONF_PATH
echo "$END_MARKER" >> $CONF_PATH
elif ! grep -q "$END_MARKER" $CONF_PATH; then
echo "ERROR: found QUBES BEGIN marker but not QUBES END in ${CONF_PATH}" >&2
echo "Fix the file by either removing both of them, or adding missing back and retry" >&2
exit 1
fi
# Prepare config block
local tmpfile=`mktemp`
cat > ${tmpfile} <<EOF
# This part of configuration, until QUBES END, is automatically generated by
# $0. All changes here will be overriden.
# If you want to override any option set here, set it again to desired value,
# below this section
$CONF_OPTIONS
EOF
# And insert it between the markers
sed -i -e "/^$BEGIN_MARKER$/,/^$END_MARKER$/{
/^$END_MARKER$/b
/^$BEGIN_MARKER$/!d
r ${tmpfile}
}" ${CONF_PATH}
rm -f ${tmpfile}
}
### helper functions end
if [ -e /etc/dnf/dnf.conf ]; then
update_conf /etc/dnf/dnf.conf "
reposdir=/etc/yum.real.repos.d
installonlypkgs = kernel, kernel-qubes-vm"
fi
if [ -e /etc/yum.conf ]; then
update_conf /etc/yum.conf "
reposdir=/etc/yum.real.repos.d
installonlypkgs = kernel, kernel-qubes-vm
distroverpkg = qubes-release"
fi

View File

@ -1,29 +1,6 @@
#!/bin/bash
escape_args() {
local eargs=""
for arg in "$@"; do
printf -v eargs '%s%q ' "$eargs" "$arg"
done
echo "${eargs%?}"
}
find_regex_in_args() {
local regex="${1}"
shift 1
for arg in "${@}"; do
if echo "${arg}" | grep -q -e "${regex}"; then
return 0
fi
done
return 1
}
UPDATEVM=`qubes-prefs --force-root updatevm`
UPDATEVM=`qubes-prefs --get updatevm`
UPDATES_STAT_FILE=/var/lib/qubes/updates/dom0-updates-available
if [ -z "$UPDATEVM" ]; then
@ -36,26 +13,24 @@ if [ "$1" = "--help" ]; then
echo "it checks for updates for installed packages"
echo ""
echo "Usage: $0 [--clean] [--check-only] [--gui] [<pkg list>]"
echo " --clean clean dnf cache before doing anything"
echo " --clean clean yum cache before doing anything"
echo " --check-only only check for updates (no install)"
echo " --gui use gpk-update-viewer for update selection"
echo " --action=... use specific dnf action, instead of automatic install/update"
echo " <pkg list> download (and install if run by root) new packages"
echo " in dom0 instead of updating"
exit
fi
PKGS=()
YUM_OPTS=()
# Prevent template upgrade - this would override user changes
TEMPLATE_EXCLUDE_OPTS="--exclude=`rpm -qa --qf '%{NAME},' qubes-template-\*`"
PKGS=
YUM_OPTS="$TEMPLATE_EXCLUDE_OPTS"
GUI=
CHECK_ONLY=
ALL_OPTS=( "${@}" )
YUM_ACTION=
ALL_OPTS="$TEMPLATE_EXCLUDE_OPTS $*"
QVMRUN_OPTS=
CLEAN=
TEMPLATE=
TEMPLATE_BACKUP=
# Filter out some dnf options and collect packages list
# Filter out some yum options and collect packages list
while [ $# -gt 0 ]; do
case "$1" in
--enablerepo=*|\
@ -70,82 +45,32 @@ while [ $# -gt 0 ]; do
--check-only)
CHECK_ONLY=1
;;
--action=*)
YUM_ACTION=${1#--action=}
;;
-*)
YUM_OPTS+=( "${1}" )
YUM_OPTS="$YUM_OPTS $1"
;;
*)
PKGS+=( "${1}" )
if [ -z "$YUM_ACTION" ]; then
YUM_ACTION=install
fi
PKGS="$PKGS $1"
;;
esac
shift
done
# Prevent implicit update of template - this would override user changes -
# but do allow explicit template upgrade, downgrade, reinstall
if [ "$YUM_ACTION" == "reinstall" ] || [ "$YUM_ACTION" == "upgrade" ] || [ "$YUM_ACTION" == "upgrade-to" ] \
|| [ "$YUM_ACTION" == "downgrade" ] && find_regex_in_args '^qubes-template-' "${PKGS[@]}"; then
TEMPLATE_EXCLUDE_OPTS=()
echo "WARNING: Replacing a template will erase all files in template's /home and /rw !"
# At least one package name matches the regex '^qubes-template-',
# so if there is only one package name in the array, then the
# code can safely assume that the array includes only a template
# package name.
if [[ ${#PKGS[@]} -eq 1 ]]; then
ONEPKG="$(echo "${PKGS[0]}" | sed -r 's/-[0-9]+(\.[0-9-]+)+(\.noarch)*$//')" # Remove version suffix
TEMPLATE=${ONEPKG#qubes-template-} # Remove prefix
if qvm-shutdown --wait $TEMPLATE ; then
echo "Template VM halted"
fi
# Try to avoid unrecoverable failures when operating on the template of
# the UpdateVM by making a backup first.
UPDATEVM_TEMPLATE=$(qvm-prefs -- "$UPDATEVM" template 2>/dev/null)
if [ X"$UPDATEVM_TEMPLATE" = X"$TEMPLATE" ]; then
TEMPLATE_BACKUP="${TEMPLATE}-backup-$(date +%Y%m%d)-$(mktemp -u XXXX)"
TEMPLATE_BACKUP=${TEMPLATE_BACKUP:0:31}
echo "Attempting to operate on template of UpdateVM... backing up $TEMPLATE to $TEMPLATE_BACKUP"
if ! qvm-clone -- "$TEMPLATE" "$TEMPLATE_BACKUP"; then
echo "ERROR: Unable to make backup of UpdateVM template!" >&2
exit 1
fi
fi
else
echo "ERROR: Specify only one package to reinstall template"
exit 1
fi
elif [ "$YUM_ACTION" == "search" ] || [ "$YUM_ACTION" == "info" ]; then # No need to shutdown for search/info
TEMPLATE_EXCLUDE_OPTS=()
else
TEMPLATE_EXCLUDE_OPTS=( "--exclude=$(rpm -qa --qf '%{NAME},' qubes-template-\*|head -c -1)" )
fi
YUM_OPTS=( "${TEMPLATE_EXCLUDE_OPTS[@]}" "${YUM_OPTS[@]}" )
ALL_OPTS=( "${TEMPLATE_EXCLUDE_OPTS[@]}" "${ALL_OPTS[@]}" )
ID=$(id -ur)
if [ $ID != 0 -a -z "$GUI" -a -z "$CHECK_ONLY" ] ; then
echo "This script should be run as root (when used in console mode), use sudo." >&2
exit 1
fi
if [ "$GUI" == "1" -a ${#PKGS[@]} -ne 0 ]; then
if [ "$GUI" == "1" -a -n "$PKGS" ]; then
echo "ERROR: GUI mode can be used only for updates" >&2
exit 1
fi
if [ "$GUI" == "1" ]; then
apps="xterm konsole yumex apper gpk-update-viewer"
apps="yumex apper gpk-update-viewer"
if [ -n "$KDE_FULL_SESSION" ]; then
apps="konsole xterm apper yumex gpk-update-viewer"
apps="apper yumex gpk-update-viewer"
fi
guiapp=
@ -153,9 +78,7 @@ if [ "$GUI" == "1" ]; then
if type $app &>/dev/null; then
guiapp=$app
case $guiapp in
apper) guiapp="apper --updates --nofork" ;;
xterm) guiapp="xterm -e sudo dnf update" ;;
konsole) guiapp="konsole --hold -e sudo dnf update" ;;
apper) guiapp="apper --updates" ;;
*) guiapp=$app ;;
esac
break;
@ -163,7 +86,7 @@ if [ "$GUI" == "1" ]; then
done
if [ -z "$guiapp" ]; then
message1="You don't have any supported dnf frontend installed."
message1="You don't have installed any supported yum frontend."
message2="Install (using qubes-dom0-update) one of: $apps"
if [ "$KDE_FULL_SESSION" ]; then
@ -180,28 +103,29 @@ if [ "$GUI" != "1" ]; then
QVMRUN_OPTS=--nogui
fi
# Do not start VM automatically when running from cron (only checking for updates)
if [ "$CHECK_ONLY" == "1" ] && ! qvm-check -q --running $UPDATEVM > /dev/null 2>&1; then
# Do not start VM automaticaly when running from cron (only checking for updates)
if [ "$CHECK_ONLY" == "1" ] && ! xl domid $UPDATEVM > /dev/null 2>&1; then
echo "ERROR: UpdateVM not running, not starting it in non-interactive mode" >&2
exit 1
fi
if [ -n "$CLEAN" ]; then
rm -f /var/lib/qubes/updates/rpm/*
rm -f /var/lib/qubes/updates/repodata/*
fi
rm -f /var/lib/qubes/updates/errors
# We should ensure the clocks in Dom0 and UpdateVM are in sync
# becuase otherwise yum might complain about future timestamps
qvm-sync-clock
echo "Using $UPDATEVM as UpdateVM to download updates for Dom0; this may take some time..." >&2
# qvm-run by default auto-starts the VM if not running
qvm-run --nogui -q -u root $UPDATEVM 'mkdir -m 775 -p /var/lib/qubes/dom0-updates/' || exit 1
qvm-run --nogui -q -u root $UPDATEVM 'chown user:user /var/lib/qubes/dom0-updates/' || exit 1
qvm-run --nogui -q $UPDATEVM 'rm -rf /var/lib/qubes/dom0-updates/etc' || exit 1
tar c /var/lib/rpm /etc/yum.repos.d /etc/yum.conf /etc/dnf/dnf.conf 2>/dev/null | \
qvm-run --nogui -q --pass-io "$UPDATEVM" 'LC_MESSAGES=C tar x -C /var/lib/qubes/dom0-updates 2>&1 | grep -v -E "s in the future"'
# Start VM if not running already
qvm-run $QVMRUN_OPTS -a $UPDATEVM true || exit 1
qvm-run $QVMRUN_OPTS --pass-io $UPDATEVM "script --quiet --return --command '/usr/lib/qubes/qubes-download-dom0-updates.sh --doit --nogui $(escape_args "${ALL_OPTS[@]}")' /dev/null" < /dev/null
tar c /var/lib/rpm /etc/yum.repos.d /etc/yum.conf 2>/dev/null | qvm-run -p "$UPDATEVM" 'tar x -C /var/lib/qubes/dom0-updates'
qvm-run $QVMRUN_OPTS --pass-io $UPDATEVM "/usr/lib/qubes/qubes-download-dom0-updates.sh --doit --nogui $ALL_OPTS"
RETCODE=$?
if [ "$CHECK_ONLY" == "1" ]; then
exit $RETCODE
@ -214,51 +138,23 @@ while pidof -x qubes-receive-updates >/dev/null; do sleep 0.5; done
if [ -r /var/lib/qubes/updates/errors ]; then
echo "*** ERROR while receiving updates:" >&2
cat /var/lib/qubes/updates/errors >&2
echo "--> if you want to use packages that were downloaded correctly, use dnf directly now" >&2
echo "--> if you want to use packages that were downloaded correctly, use yum directly now" >&2
exit 1
fi
if [ -z "$YUM_ACTION" ]; then
YUM_ACTION=upgrade
fi
if [ ${#PKGS[@]} -gt 0 ]; then
if [ -n "$TEMPLATE" ]; then
TEMPLATE_NETVM=$(qvm-prefs --force-root $TEMPLATE netvm)
fi
dnf "${YUM_OPTS[@]}" $YUM_ACTION "${PKGS[@]}" ; RETCODE=$?
if [ -n "$TEMPLATE_BACKUP" -a "$RETCODE" -eq 0 ]; then
# Remove backup, if we made one. Better to do this only on success and
# potentially leave extra backups around than do it on an exit trap and
# clean up more reliably but potentially brick a system.
qvm-remove -f -- "$TEMPLATE_BACKUP"
fi
if [ -n "$TEMPLATE" -a -n "$TEMPLATE_NETVM" -a x"$TEMPLATE_NETVM" != xNone ]; then
if ! qvm-prefs --force-root -s $TEMPLATE netvm $TEMPLATE_NETVM; then
echo "ERROR: NetVM setting could not be restored!" >&2
exit 1
fi
fi
if [ "x$PKGS" != "x" ]; then
yum $YUM_OPTS install $PKGS
elif [ -f /var/lib/qubes/updates/repodata/repomd.xml ]; then
# Above file exists only when at least one package was downloaded
if [ "$GUI" == "1" ]; then
# refresh packagekit metadata, GUI utilities use it
pkcon refresh force
$guiapp
else
dnf check-update
if [ $? -eq 100 ]; then # Run dnf with options
dnf "${YUM_OPTS[@]}" $YUM_ACTION
yum check-update
if [ $? -eq 100 ]; then
yum $YUM_OPTS update
fi
fi
dnf -q check-update && qvm-features dom0 updates-available ''
yum -q check-update && rm -f $UPDATES_STAT_FILE
else
qvm-features dom0 updates-available ''
echo "No updates available" >&2
if [ "$GUI" == "1" ]; then
zenity --info --title='Dom0 updates' --text='No updates available'
fi
echo "No updates avaliable" >&2
fi

View File

@ -1,6 +1,12 @@
#!/bin/bash
if [ "$(qvm-features dom0 service.qubes-update-check || echo 1)" != 1 ]; then
# Get normal user name
LOCAL_USER=`users | sed -e 's/root *//' | cut -d' ' -f 1`
NOTIFY_ICON=/usr/share/qubes/icons/dom0-update-avail.svg
UPDATES_STAT_FILE=/var/lib/qubes/updates/dom0-updates-available
UPDATES_DISABLE_FLAG=/var/lib/qubes/updates/disable-updates
if [ -f "$UPDATES_DISABLE_FLAG" ]; then
exit 0
fi
@ -13,4 +19,10 @@ if [ "$RETCODE" -ne 100 ]; then
exit $RETCODE
fi
qvm-features dom0 updates-available 1
if [ -z "$LOCAL_USER" ]; then
echo "ERROR: no user logged in, cannot nofity about updates" >&2
exit 1
fi
# Touch stat file for qubes-manager
touch $UPDATES_STAT_FILE

View File

@ -1,4 +1,4 @@
#!/usr/bin/python3
#!/usr/bin/python2
#
# The Qubes OS Project, http://www.qubes-os.org
#
@ -18,49 +18,50 @@
# 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 glob
import grp
import qubesadmin
from qubes.qubes import QubesVmCollection
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$")
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
# .....rpm: digests signatures OK
# example INVALID outputs:
# .....rpm: sha1 md5 OK
# .....rpm: RSA sha1 ((MD5) PGP) md5 NOT OK (MISSING KEYS: (MD5) PGP#246110c1)
# .....rpm: digests OK
gpg_ok_regex = re.compile(r": [a-z0-9() ]* (pgp|gpg|signatures) [a-z0-9 ]*OK$")
def dom0updates_fatal(msg):
print(msg, file=sys.stderr)
with open(updates_error_file, "a") as updates_error_file_handle:
updates_error_file_handle.write(msg + "\n")
shutil.rmtree(updates_rpm_dir)
exit(1)
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 >> sys.stderr, msg
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):
source = os.getenv("QREXEC_REMOTE_DOMAIN")
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)
print >> sys.stderr, 'Domain ' + str(source) + ' not allowed to send dom0 updates'
exit(1)
# Clean old packages
if os.path.exists(updates_rpm_dir):
@ -71,18 +72,15 @@ def handle_dom0updates(updatevm):
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)
try:
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):
raise Exception(
'Domain ' + source + ' sent unexpected file')
os.chmod(updates_rpm_dir, 0775)
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
@ -90,42 +88,45 @@ def handle_dom0updates(updatevm):
full_path = updates_rpm_dir + "/" + f
if os.path.islink(full_path) or not os.path.isfile(full_path):
raise Exception(
'Domain ' + source + ' sent not regular file')
p = subprocess.Popen(["/bin/rpm", "-K", 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')
output = p.communicate()[0]
if p.returncode != 0:
raise Exception(
'Error while verifing %s signature: %s' % (f, output))
dom0updates_fatal(full_path, 'Error while verifing %s signature: %s' % (f, output))
if not gpg_ok_regex.search(output.strip()):
raise Exception(
'Domain ' + source + ' sent not signed rpm: ' + f)
except Exception as e:
dom0updates_fatal(str(e))
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"]
createrepo_cmd = ["/usr/bin/createrepo"]
if comps_file:
createrepo_cmd += ["-g", comps_file]
createrepo_cmd += ["-q", updates_dir]
old_umask = os.umask(002)
subprocess.check_call(createrepo_cmd)
os.chown(updates_repodata_dir, -1, qubes_gid)
os.chmod(updates_repodata_dir, 0o0775)
os.chmod(updates_repodata_dir, 0775)
# Clean old cache
subprocess.call(["sudo", "/usr/bin/yum", "-q", "clean", "all"],
stdout=sys.stderr)
subprocess.call(["sudo", "/usr/bin/yum", "-q", "clean", "all"], stdout=sys.stderr)
# This will fail because of "smart" detection of no-network, but it will invalidate the cache
try:
null = open('/dev/null','w')
subprocess.call(["/usr/bin/pkcon", "refresh"], stdout=null)
null.close()
except:
pass
os.umask(old_umask)
exit(0)
def main():
app = qubesadmin.Qubes()
qvm_collection = QubesVmCollection()
qvm_collection.lock_db_for_reading()
qvm_collection.load()
qvm_collection.unlock_db()
updatevm = app.updatevm
if updatevm is None:
exit(1)
updatevm = qvm_collection.get_updatevm_vm()
handle_dom0updates(updatevm)
if __name__ == '__main__':
main()
main()

View File

@ -0,0 +1,4 @@
# Apprently some of the drivers required when using a processor with AESNI for LUKS
# are missing in the initramfs, so lets include them manually here:
add_drivers+=" xts aesni-intel aes-x86_64 crc32c-intel ghash-clmulni-intel salsa20-x86_64 twofish-x86_64 "

View File

@ -1,6 +0,0 @@
# Omission of network and kernel-network-modules is needed
# to avoid letting the initramfs load kernel modules related
# to networking, even if PCI devices are seized by Xen's
# pciback kernel module.
omit_dracutmodules+=" network kernel-network-modules "

View File

@ -3,9 +3,5 @@
installkernel() {
# ehci-hcd split off
hostonly='' instmods ehci-pci ehci-platform || :
# xhci-hcd split off
hostonly='' instmods xhci-pci xhci-plat-hcd || :
# ohci-hcd split off
hostonly='' instmods ohci-pci || :
instmods ehci-pci ehci-platform || :
}

View File

@ -1,16 +0,0 @@
#!/usr/bin/bash
# Add roadrunner2/macbook12-spi-driver drivers to initramfs for supporting keyboard, touchpad, touchbar in the MacBooks.
# Pre-requisite: these drivers need to be included in the Linux kernel package.
check() {
grep -q ^MacBook /sys/devices/virtual/dmi/id/product_name || return 255
}
installkernel() {
hostonly='' instmods intel_lpss intel_lpss_pci spi_pxa2xx_platform spi_pxa2xx_pci applespi apple_ib_tb
}
install() {
echo "options apple_ib_tb fnmode=2" >> "${initdir}/etc/modprobe.d/macbook12-spi-driver.conf"
echo "options applespi fnremap=1" >> "${initdir}/etc/modprobe.d/macbook12-spi-driver.conf"
}

View File

@ -1,7 +1,3 @@
#!/bin/bash
for mod in pciback xen-pciback; do
if modinfo -k "${kernel}" "${mod}" >/dev/null 2>&1; then
instmods "${mod}"
fi
done
modinfo -k $kernel pciback > /dev/null 2>&1 && instmods pciback
modinfo -k $kernel xen-pciback > /dev/null 2>&1 && instmods xen-pciback

View File

@ -8,11 +8,6 @@ install() {
}
installkernel() {
local mod=
for mod in pciback xen-pciback; do
if modinfo -k "${kernel}" "${mod}" >/dev/null 2>&1; then
hostonly='' instmods "${mod}"
fi
done
modinfo -k $kernel pciback > /dev/null 2>&1 && hostonly='' instmods pciback
modinfo -k $kernel xen-pciback > /dev/null 2>&1 && hostonly='' instmods xen-pciback
}

View File

@ -3,23 +3,14 @@
type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh
# Find all networking devices currenly installed...
HIDE_PCI="`lspci -mm -n | grep '^[^ ]* "02'|awk '{print $1}'`"
HIDE_PCI=`lspci -mm -n | grep '^[^ ]* "02'|awk '{ ORS="";print "(" $1 ")";}'`
# ... and optionally all USB controllers...
if getargbool 0 rd.qubes.hide_all_usb; then
HIDE_PCI="$HIDE_PCI `lspci -mm -n | grep '^[^ ]* "0c03'|awk '{print $1}'`"
HIDE_PCI=$HIDE_PCI`lspci -mm -n | grep '^[^ ]* "0c03'|awk '{ ORS="";print "(" $1 ")";}'`
fi
HIDE_PCI="$HIDE_PCI `getarg rd.qubes.hide_pci | tr ',' ' '`"
modprobe xen-pciback 2>/dev/null || :
HIDE_PCI=$HIDE_PCI`getarg rd.qubes.hide_pci | tr ',' '\n'|awk '{ ORS="";print "(" $1 ")";}'`
# ... and hide them so that Dom0 doesn't load drivers for them
for dev in $HIDE_PCI; do
BDF=0000:$dev
if [ -e /sys/bus/pci/devices/$BDF/driver ]; then
echo -n $BDF > /sys/bus/pci/devices/$BDF/driver/unbind
fi
echo -n $BDF > /sys/bus/pci/drivers/pciback/new_slot
echo -n $BDF > /sys/bus/pci/drivers/pciback/bind
done
modprobe pciback hide=$HIDE_PCI 2> /dev/null || modprobe xen-pciback hide=$HIDE_PCI

View File

@ -1,8 +0,0 @@
CFLAGS=-g -O2 -Wall -Wextra -Werror -I. -fPIC -pie
all: qfile-dom0-agent
qfile-dom0-agent: qfile-dom0-agent.o
$(CC) -pie -g -o $@ $^ -lqubes-rpc-filecopy
clean:
rm -f qfile-dom0-agent *.o

View File

@ -1,94 +0,0 @@
#define _GNU_SOURCE
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <signal.h>
#include <fcntl.h>
#include <malloc.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <libqubes-rpc-filecopy.h>
void display_error(const char *fmt, va_list args) {
char *dialog_cmd;
char buf[1024];
struct stat st_buf;
int ret;
(void) vsnprintf(buf, sizeof(buf), fmt, args);
ret = stat("/usr/bin/kdialog", &st_buf);
#define KDIALOG_CMD "kdialog --title 'File copy/move error' --sorry "
#define ZENITY_CMD "zenity --title 'File copy/move error' --warning --text "
if (asprintf(&dialog_cmd, "%s '%s: %s (error type: %s)'",
ret==0 ? KDIALOG_CMD : ZENITY_CMD,
program_invocation_short_name, buf, strerror(errno)) < 0) {
fprintf(stderr, "Failed to allocate memory for error message :(\n");
return;
}
#undef KDIALOG_CMD
#undef ZENITY_CMD
fprintf(stderr, "%s\n", buf);
system(dialog_cmd);
}
_Noreturn void gui_fatal(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
display_error(fmt, args);
va_end(args);
exit(1);
}
char *get_abs_path(const char *cwd, const char *pathname)
{
char *ret;
if (pathname[0] == '/')
return strdup(pathname);
if (asprintf(&ret, "%s/%s", cwd, pathname) < 0)
return NULL;
else
return ret;
}
int main(int argc, char **argv)
{
int i;
char *entry;
char *cwd;
char *sep;
int ignore_symlinks = 0;
qfile_pack_init();
register_error_handler(display_error);
cwd = getcwd(NULL, 0);
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "--ignore-symlinks")==0) {
ignore_symlinks = 1;
continue;
}
entry = get_abs_path(cwd, argv[i]);
do {
sep = rindex(entry, '/');
if (!sep)
gui_fatal
("Internal error: nonabsolute filenames not allowed");
*sep = 0;
} while (sep[1] == 0);
if (entry[0] == 0) {
if (chdir("/") < 0) {
gui_fatal("Internal error: chdir(\"/\") failed?!");
}
} else if (chdir(entry))
gui_fatal("chdir to %s", entry);
do_fs_walk(sep + 1, ignore_symlinks);
free(entry);
}
notify_end_and_wait_for_result();
return 0;
}

View File

@ -1,26 +0,0 @@
#!/bin/bash
set -e -o pipefail
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2015 Marek Marczykowski-Górecki <marmarek@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.
#
#
echo "${0##*/} is not supported in dom0; use ${0##*/}-to-vm instead."
exit 1

View File

@ -1,43 +0,0 @@
#!/bin/bash
set -e -o pipefail
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2015 Marek Marczykowski-Górecki <marmarek@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.
#
#
if [ $# -lt 2 ] ; then
echo usage: $0 'dest_vmname file [file]+'
exit 1
fi
VM="$1"
shift
TMPDIR=`mktemp -d`
trap 'rm -rf -- "$TMPDIR"' EXIT
RESPONSE=$TMPDIR/response
mkfifo -- "$RESPONSE"
# can't use $@ with --localcmd, and $* would fail on whitespace
/usr/lib/qubes/qfile-dom0-agent "$@" <"$RESPONSE" |
qvm-run --pass-io --service -- "$VM" "qubes.Filecopy" >"$RESPONSE"
if [ "${0##*/}" = "qvm-move-to-vm" ]; then
rm -rf -- "$@"
fi

BIN
icons/black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

BIN
icons/blue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

View File

@ -0,0 +1,10 @@
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
This copyright and license notice covers the images in this directory.
************************************************************************
TITLE: Crystal Project Icons
AUTHOR: Everaldo Coelho
SITE: http://www.everaldo.com
CONTACT: everaldo@everaldo.com
Copyright (c) 2006-2007 Everaldo Coelho.

View File

@ -0,0 +1 @@
dom0-update-avail icon from gnome-packagekit project distributed under GPLv2

View File

@ -0,0 +1 @@
Color padlock images downloaded from www.openclipart.org

BIN
icons/dispvm-black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
icons/dispvm-blue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
icons/dispvm-gray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
icons/dispvm-green.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
icons/dispvm-orange.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

BIN
icons/dispvm-purple.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
icons/dispvm-red.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
icons/dispvm-yellow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
icons/dom0-update-avail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
icons/gray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

BIN
icons/green.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

BIN
icons/netvm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
icons/orange.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

BIN
icons/purple.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

BIN
icons/qubes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
icons/red.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

BIN
icons/template.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
icons/yellow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

22
pm-utils/01qubes-sync-vms-clock Executable file
View File

@ -0,0 +1,22 @@
#!/bin/sh
sync_qubes_vms_wallclock()
{
# Sync all VMs based on dom0 clock
DATE=$(date)
echo
echo "Syncing VMs clock to: $DATE"
qvm-run --all -u root "date -s \"$DATE\""
# Then try to sync from the network
/usr/bin/qvm-sync-clock &
}
case "$1" in
thaw|resume) sync_qubes_vms_wallclock ;;
# Kill qvm-sync-clock (if running) to not desync time after resume
suspend|hibernate)
killall qvm-sync-clock 2> /dev/null
exit 0
;;
*) exit 0 ;;
esac

37
pm-utils/51qubes-suspend-netvm Executable file
View File

@ -0,0 +1,37 @@
#!/bin/sh
get_running_netvms() {
# Actually get running VMs with PCI devices attached
RUNNING_VMS=`xl list | tail -n +3 | cut -f 1 -d " "`
RUNNING_NETVMS=""
for VM in $RUNNING_VMS; do
if [ -n "`xl pci-list $VM|tail -n +2`" ]; then
echo "$VM"
fi
done
}
suspend_net()
{
for VM in `get_running_netvms`; do
qvm-run -u root --pass-io $VM 'QUBESRPC qubes.SuspendPre dom0'
done
# Ignore exit status from netvm...
return 0
}
resume_net()
{
for VM in `get_running_netvms`; do
qvm-run -u root --pass-io $VM 'QUBESRPC qubes.SuspendPost dom0'
done
# Ignore exit status from netvm...
return 0
}
case "$1" in
resume) resume_net ;;
suspend) suspend_net ;;
*) exit 0 ;;
esac

View File

@ -1,12 +1,25 @@
#!/bin/sh
#!/usr/bin/python
case "$1" in
suspend|hibernate)
qubesd-query -e --fail -c /var/run/qubesd.internal.sock \
dom0 internal.SuspendPre dom0 | tr '\0' ' '
;;
resume|thaw)
qubesd-query -e --fail -c /var/run/qubesd.internal.sock \
dom0 internal.SuspendPost dom0 | tr '\0' ' '
;;
esac
from qubes.qubes import QubesVmCollection,QubesException
import sys
qc = QubesVmCollection()
qc.lock_db_for_reading()
qc.load()
qc.unlock_db()
if sys.argv[1] in ["suspend", "hibernate"]:
for vm in qc.values():
if vm.is_running():
try:
vm.suspend()
except Exception as e:
print >>sys.stderr, "Failed to suspend VM %s: %s" % (vm.name, e.message)
elif sys.argv[1] in ["resume", "thaw"]:
for vm in qc.values():
if vm.get_power_state() in ["Paused", "Suspended"]:
try:
vm.resume()
except Exception as e:
print >>sys.stderr, "Failed to resume VM %s: %s" % (vm.name, e.message)

View File

@ -7,8 +7,12 @@ StopWhenUnneeded=yes
Type=oneshot
RemainAfterExit=yes
StandardOutput=syslog
ExecStartPre=/usr/lib64/pm-utils/sleep.d/01qubes-sync-vms-clock suspend suspend
ExecStartPre=/usr/lib64/pm-utils/sleep.d/51qubes-suspend-netvm suspend suspend
ExecStart=/usr/lib64/pm-utils/sleep.d/52qubes-pause-vms suspend suspend
ExecStop=/usr/lib64/pm-utils/sleep.d/52qubes-pause-vms resume suspend
ExecStopPost=/usr/lib64/pm-utils/sleep.d/51qubes-suspend-netvm resume suspend
ExecStopPost=/usr/lib64/pm-utils/sleep.d/01qubes-sync-vms-clock resume suspend
[Install]
WantedBy=sleep.target

12
qrexec/Makefile Normal file
View File

@ -0,0 +1,12 @@
CC=gcc
CFLAGS+=-I. -g -Wall -Wextra -Werror -pie -fPIC
XENLIBS=-lvchan -lxenstore -lxenctrl
LIBS=$(XENLIBS) -lqrexec-utils
all: qrexec-daemon qrexec-client
qrexec-daemon: qrexec-daemon.o
$(CC) -pie -g -o qrexec-daemon qrexec-daemon.o $(LIBS)
qrexec-client: qrexec-client.o
$(CC) -pie -g -o qrexec-client qrexec-client.o $(LIBS) -lpthread
clean:
rm -f *.o *~ qrexec-daemon qrexec-client

64
qrexec/README.rpc Normal file
View File

@ -0,0 +1,64 @@
Currently (after commit 2600134e3bb781fca25fe77e464f8b875741dc83),
qrexec_agent can request a service (specified by a "exec_index") to be
executed on a different VM or dom0. Access control is enforced in dom0 via
files in /etc/qubes_rpc/policy. File copy, Open in Dispvm, sync appmenus,
upload updates to dom0 - they all have been ported to the new API.
See the quick HOWTO section on how to add a new service. Note we have
qvm-open-in-vm utility practically for free.
CHANGES
Besides flexibility offered by /etc/qubes_rpc/policy, writing a client
is much simpler now. The workflow used to be (using "filecopy" service as
an example):
a) "filecopy_ui" process places job description in some spool directory,
signals qrexec_agent to signal qrexec_daemon
b) qrexec_daemon executes "qrexec_client -d domain filecopy_worker ...."
and "filecopy_worker" process needed to parse spool and retrieve job
description from there. Particularly, "filecopy_ui" had no connection to
remote.
Now, the flow is:
a) qrexec_client_vm process obtains 3 unix socket descriptors from
qrexec_agent, dup stdin/out/err to them; forms "existing_process_handle" from
them
b) qrexec_client_vm signals qrexec_agent to signal qrexec_daemon, with a
"exec_index" (so, type of service) as an argument
c) qrexec_daemon executed "qrexec_client -d domain -c existing_process_handle ...."
d) qrexec_client_vm execve filecopy_program.
Thus, there is only one service program, and it has direct access to remote via
stdin/stdout.
HOWTO
Let's add a new "test.Add" service, that will add two numbers. We need the
following files in the template fs:
==========================
/usr/bin/our_test_add_client:
#!/bin/sh
echo $1 $2
exec cat >&2
# more correct: exec cat >&$SAVED_FD_1, but do not scare the reader
==========================
/usr/bin/our_test_add_server:
#!/bin/sh
read arg1 arg2
echo $(($arg1+$arg2))
==========================
/etc/qubes_rpc/test.Add:
/usr/bin/our_test_add_server
Now, on the client side, we start the client via
/usr/lib/qubes/qrexec_client_vm target_vm test.Add /usr/bin/our_test_add_client 11 22
Because there is no policy yet, dom0 will ask you to create one (of cource you
can do it before the first run of our_test_add_client). So, in dom0, create (by now,
with a file editor) the /etc/qubes_rpc/policy/test.Add file with
anyvm anyvm ask
content. The format of the /etc/qubes_rpc/policy/* files is
srcvm destvm (allow|deny|ask)[,user=user_to_run_as][,target=VM_to_redirect_to]
You can specify srcvm and destvm by name, or by one of "anyvm", "dispvm", "dom0"
reserved keywords.
Then, when you confirm the operation, you will get the result in the client vm.

314
qrexec/qrexec-client.c Normal file
View File

@ -0,0 +1,314 @@
/*
* 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.
*
*/
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
#include <pthread.h>
#include "qrexec.h"
#include "libqrexec-utils.h"
// whether qrexec-client should replace ESC with _ before printing the output
int replace_esc_stdout = 0;
int replace_esc_stderr = 0;
int connect_unix_socket(const char *domname)
{
int s, len;
struct sockaddr_un remote;
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
return -1;
}
remote.sun_family = AF_UNIX;
snprintf(remote.sun_path, sizeof remote.sun_path,
QREXEC_DAEMON_SOCKET_DIR "/qrexec.%s", domname);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
if (connect(s, (struct sockaddr *) &remote, len) == -1) {
perror("connect");
exit(1);
}
return s;
}
void do_exec(const char *prog)
{
execl("/bin/bash", "bash", "-c", prog, NULL);
}
static int local_stdin_fd, local_stdout_fd;
void do_exit(int code)
{
int status;
// sever communication lines; wait for child, if any
// so that qrexec-daemon can count (recursively) spawned processes correctly
close(local_stdin_fd);
close(local_stdout_fd);
waitpid(-1, &status, 0);
exit(code);
}
void prepare_local_fds(const char *cmdline)
{
int pid;
if (!cmdline) {
local_stdin_fd = 1;
local_stdout_fd = 0;
return;
}
do_fork_exec(cmdline, &pid, &local_stdin_fd, &local_stdout_fd,
NULL);
}
void send_cmdline(int s, int type, const char *cmdline)
{
struct client_header hdr;
hdr.type = type;
hdr.len = strlen(cmdline) + 1;
if (!write_all(s, &hdr, sizeof(hdr))
|| !write_all(s, cmdline, hdr.len)) {
perror("write daemon");
do_exit(1);
}
}
void handle_input(int s)
{
char buf[MAX_DATA_CHUNK];
int ret;
ret = read(local_stdout_fd, buf, sizeof(buf));
if (ret < 0) {
perror("read");
do_exit(1);
}
if (ret == 0) {
close(local_stdout_fd);
local_stdout_fd = -1;
shutdown(s, SHUT_WR);
if (local_stdin_fd == -1) {
// if pipe in opposite direction already closed, no need to stay alive
do_exit(0);
}
}
if (!write_all(s, buf, ret)) {
if (errno == EPIPE) {
// daemon disconnected its end of socket, so no future data will be
// send there; there is no sense to read from child stdout
//
// since AF_UNIX socket is buffered it doesn't mean all data was
// received from the agent
close(local_stdout_fd);
local_stdout_fd = -1;
if (local_stdin_fd == -1) {
// since child does no longer accept data on its stdin, doesn't
// make sense to process the data from the daemon
//
// we don't know real exit VM process code (exiting here, before
// MSG_SERVER_TO_CLIENT_EXIT_CODE message)
do_exit(1);
}
} else
perror("write daemon");
}
}
void do_replace_esc(char *buf, int len) {
int i;
for (i = 0; i < len; i++)
if (buf[i] == '\033')
buf[i] = '_';
}
void handle_daemon_data(int s)
{
int status;
struct client_header hdr;
char buf[MAX_DATA_CHUNK], *bufptr=buf;
if (!read_all(s, &hdr, sizeof hdr)) {
perror("read daemon");
do_exit(1);
}
if (hdr.len > MAX_DATA_CHUNK) {
fprintf(stderr, "client_header.len=%d\n", hdr.len);
do_exit(1);
}
if (!read_all(s, buf, hdr.len)) {
perror("read daemon");
do_exit(1);
}
switch (hdr.type) {
case MSG_SERVER_TO_CLIENT_STDOUT:
if (replace_esc_stdout)
do_replace_esc(buf, hdr.len);
if (local_stdin_fd == -1)
break;
if (hdr.len == 0) {
close(local_stdin_fd);
local_stdin_fd = -1;
} else if (!write_all(local_stdin_fd, buf, hdr.len)) {
if (errno == EPIPE) {
// remote side have closed its stdin, handle data in oposite
// direction (if any) before exit
local_stdin_fd = -1;
} else {
perror("write local stdout");
do_exit(1);
}
}
break;
case MSG_SERVER_TO_CLIENT_STDERR:
if (replace_esc_stderr)
do_replace_esc(buf, hdr.len);
write_all(2, buf, hdr.len);
break;
case MSG_SERVER_TO_CLIENT_EXIT_CODE:
status = *(unsigned int *) bufptr;
if (WIFEXITED(status))
do_exit(WEXITSTATUS(status));
else
do_exit(255);
break;
default:
fprintf(stderr, "unknown msg %d\n", hdr.type);
do_exit(1);
}
}
// perhaps we could save a syscall if we include both sides in both
// rdset and wrset; to be investigated
void handle_daemon_only_until_writable(int s)
{
fd_set rdset, wrset;
do {
FD_ZERO(&rdset);
FD_ZERO(&wrset);
FD_SET(s, &rdset);
FD_SET(s, &wrset);
if (select(s + 1, &rdset, &wrset, NULL, NULL) < 0) {
perror("select");
do_exit(1);
}
if (FD_ISSET(s, &rdset))
handle_daemon_data(s);
} while (!FD_ISSET(s, &wrset));
}
void *input_process_loop(void *arg) {
int s = *(int*)arg;
while (local_stdout_fd != -1)
handle_input(s);
return NULL;
}
void select_loop(int s)
{
pthread_t input_thread;
if (pthread_create(&input_thread, NULL, input_process_loop, &s) != 0) {
perror("pthread_create");
do_exit(1);
}
for (;;) {
handle_daemon_data(s);
}
pthread_join(input_thread, NULL);
}
void usage(const char *name)
{
fprintf(stderr,
"usage: %s -d domain_num [-l local_prog] -e -t -T -c remote_cmdline\n"
"-e means exit after sending cmd, -c: connect to existing process\n"
"-t enables replacing ESC character with '_' in command output, -T is the same for stderr\n",
name);
exit(1);
}
int main(int argc, char **argv)
{
int opt;
char *domname = NULL;
int s;
int just_exec = 0;
int connect_existing = 0;
char *local_cmdline = NULL;
while ((opt = getopt(argc, argv, "d:l:ectT")) != -1) {
switch (opt) {
case 'd':
domname = strdup(optarg);
break;
case 'l':
local_cmdline = strdup(optarg);
break;
case 'e':
just_exec = 1;
break;
case 'c':
connect_existing = 1;
break;
case 't':
replace_esc_stdout = 1;
break;
case 'T':
replace_esc_stderr = 1;
break;
default:
usage(argv[0]);
}
}
if (optind >= argc || !domname)
usage(argv[0]);
register_exec_func(&do_exec);
s = connect_unix_socket(domname);
setenv("QREXEC_REMOTE_DOMAIN", domname, 1);
prepare_local_fds(local_cmdline);
if (just_exec)
send_cmdline(s, MSG_CLIENT_TO_SERVER_JUST_EXEC,
argv[optind]);
else {
int cmd;
if (connect_existing)
cmd = MSG_CLIENT_TO_SERVER_CONNECT_EXISTING;
else
cmd = MSG_CLIENT_TO_SERVER_EXEC_CMDLINE;
send_cmdline(s, cmd, argv[optind]);
select_loop(s);
}
return 0;
}

717
qrexec/qrexec-daemon.c Normal file
View File

@ -0,0 +1,717 @@
/*
* 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.
*
*/
#include <sys/select.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <string.h>
#include "qrexec.h"
#include "libqrexec-utils.h"
enum client_flags {
CLIENT_INVALID = 0, // table slot not used
CLIENT_CMDLINE = 1, // waiting for cmdline from client
CLIENT_DATA = 2, // waiting for data from client
CLIENT_DONT_READ = 4, // don't read from the client, the other side pipe is full, or EOF (additionally marked with CLIENT_EOF)
CLIENT_OUTQ_FULL = 8, // don't write to client, its stdin pipe is full
CLIENT_EOF = 16, // got EOF
CLIENT_EXITED = 32 // only send remaining data from client and remove from list
};
struct _client {
int state; // combination of above enum client_flags
struct buffer buffer; // buffered data to client, if any
};
/*
The "clients" array is indexed by client's fd.
Thus its size must be equal MAX_FDS; defining MAX_CLIENTS for clarity.
*/
#define MAX_CLIENTS MAX_FDS
struct _client clients[MAX_CLIENTS]; // data on all qrexec_client connections
int max_client_fd = -1; // current max fd of all clients; so that we need not to scan all the "clients" table
int qrexec_daemon_unix_socket_fd; // /var/run/qubes/qrexec.xid descriptor
const char *default_user = "user";
const char default_user_keyword[] = "DEFAULT:";
#define default_user_keyword_len_without_colon (sizeof(default_user_keyword)-2)
int opt_quiet = 0;
#ifdef __GNUC__
# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
#else
# define UNUSED(x) UNUSED_ ## x
#endif
/*
we need to track the number of children, so that excessive QREXEC_EXECUTE_*
commands do not fork-bomb dom0
*/
volatile int children_count;
void sigusr1_handler(int UNUSED(x))
{
if (!opt_quiet)
fprintf(stderr, "connected\n");
exit(0);
}
void sigchld_parent_handler(int UNUSED(x))
{
children_count--;
/* starting value is 0 so we see dead real qrexec-daemon as -1 */
if (children_count < 0) {
if (!opt_quiet)
fprintf(stderr, "failed\n");
else
fprintf(stderr, "Connection to the VM failed\n");
exit(1);
}
}
void sigchld_handler(int x);
const char *remote_domain_name; // guess what
int remote_domain_xid; // guess what
void unlink_qrexec_socket()
{
char socket_address[40];
char link_to_socket_name[strlen(remote_domain_name) + sizeof(socket_address)];
snprintf(socket_address, sizeof(socket_address),
QREXEC_DAEMON_SOCKET_DIR "/qrexec.%d", remote_domain_xid);
snprintf(link_to_socket_name, sizeof link_to_socket_name,
QREXEC_DAEMON_SOCKET_DIR "/qrexec.%s", remote_domain_name);
unlink(socket_address);
unlink(link_to_socket_name);
}
int create_qrexec_socket(int domid, const char *domname)
{
char socket_address[40];
char link_to_socket_name[strlen(domname) + sizeof(socket_address)];
snprintf(socket_address, sizeof(socket_address),
QREXEC_DAEMON_SOCKET_DIR "/qrexec.%d", domid);
snprintf(link_to_socket_name, sizeof link_to_socket_name,
QREXEC_DAEMON_SOCKET_DIR "/qrexec.%s", domname);
unlink(link_to_socket_name);
if (symlink(socket_address, link_to_socket_name)) {
fprintf(stderr, "symlink(%s,%s) failed: %s\n", socket_address,
link_to_socket_name, strerror (errno));
}
atexit(unlink_qrexec_socket);
return get_server_socket(socket_address);
}
#define MAX_STARTUP_TIME_DEFAULT 60
/* do the preparatory tasks, needed before entering the main event loop */
void init(int xid)
{
char qrexec_error_log_name[256];
int logfd;
int i;
pid_t pid;
int startup_timeout = MAX_STARTUP_TIME_DEFAULT;
const char *startup_timeout_str = NULL;
if (xid <= 0) {
fprintf(stderr, "domain id=0?\n");
exit(1);
}
startup_timeout_str = getenv("QREXEC_STARTUP_TIMEOUT");
if (startup_timeout_str) {
startup_timeout = atoi(startup_timeout_str);
if (startup_timeout <= 0)
// invalid or negative number
startup_timeout = MAX_STARTUP_TIME_DEFAULT;
}
signal(SIGUSR1, sigusr1_handler);
signal(SIGCHLD, sigchld_parent_handler);
switch (pid=fork()) {
case -1:
perror("fork");
exit(1);
case 0:
break;
default:
if (getenv("QREXEC_STARTUP_NOWAIT"))
exit(0);
if (!opt_quiet)
fprintf(stderr, "Waiting for VM's qrexec agent.");
for (i=0;i<startup_timeout;i++) {
sleep(1);
if (!opt_quiet)
fprintf(stderr, ".");
if (i==startup_timeout-1) {
break;
}
}
fprintf(stderr, "Cannot connect to qrexec agent for %d seconds, still trying in the background\n", startup_timeout);
exit(1);
}
close(0);
snprintf(qrexec_error_log_name, sizeof(qrexec_error_log_name),
"/var/log/qubes/qrexec.%s.log", remote_domain_name);
umask(0007); // make the log readable by the "qubes" group
logfd =
open(qrexec_error_log_name, O_WRONLY | O_CREAT | O_TRUNC,
0640);
if (logfd < 0) {
perror("open");
exit(1);
}
dup2(logfd, 1);
dup2(logfd, 2);
chdir("/var/run/qubes");
if (setsid() < 0) {
perror("setsid()");
exit(1);
}
peer_client_init(xid, REXEC_PORT);
if (setgid(getgid()) < 0) {
perror("setgid()");
exit(1);
}
if (setuid(getuid()) < 0) {
perror("setuid()");
exit(1);
}
/* When running as root, make the socket accessible; perms on /var/run/qubes still apply */
umask(0);
qrexec_daemon_unix_socket_fd =
create_qrexec_socket(xid, remote_domain_name);
umask(0077);
signal(SIGPIPE, SIG_IGN);
signal(SIGCHLD, sigchld_handler);
signal(SIGUSR1, SIG_DFL);
kill(getppid(), SIGUSR1); // let the parent know we are ready
}
void handle_new_client(void)
{
int fd = do_accept(qrexec_daemon_unix_socket_fd);
if (fd >= MAX_CLIENTS) {
fprintf(stderr, "too many clients ?\n");
exit(1);
}
clients[fd].state = CLIENT_CMDLINE;
buffer_init(&clients[fd].buffer);
if (fd > max_client_fd)
max_client_fd = fd;
}
void terminate_client_and_flush_data(int fd)
{
int i;
struct server_header s_hdr;
if (!(clients[fd].state & CLIENT_EXITED) && fork_and_flush_stdin(fd, &clients[fd].buffer))
children_count++;
close(fd);
clients[fd].state = CLIENT_INVALID;
buffer_free(&clients[fd].buffer);
if (max_client_fd == fd) {
for (i = fd; i >= 0 && clients[i].state == CLIENT_INVALID;
i--);
max_client_fd = i;
}
s_hdr.type = MSG_SERVER_TO_AGENT_CLIENT_END;
s_hdr.client_id = fd;
s_hdr.len = 0;
write_all_vchan_ext(&s_hdr, sizeof(s_hdr));
}
int get_cmdline_body_from_client_and_pass_to_agent(int fd, struct server_header
*s_hdr)
{
int len = s_hdr->len;
char buf[len];
int use_default_user = 0;
if (!read_all(fd, buf, len)) {
terminate_client_and_flush_data(fd);
return 0;
}
if (!strncmp(buf, default_user_keyword, default_user_keyword_len_without_colon+1)) {
use_default_user = 1;
s_hdr->len -= default_user_keyword_len_without_colon; // -1 because of colon
s_hdr->len += strlen(default_user);
}
write_all_vchan_ext(s_hdr, sizeof(*s_hdr));
if (use_default_user) {
write_all_vchan_ext(default_user, strlen(default_user));
write_all_vchan_ext(buf+default_user_keyword_len_without_colon, len-default_user_keyword_len_without_colon);
} else
write_all_vchan_ext(buf, len);
return 1;
}
void handle_cmdline_message_from_client(int fd)
{
struct client_header hdr;
struct server_header s_hdr;
if (!read_all(fd, &hdr, sizeof hdr)) {
terminate_client_and_flush_data(fd);
return;
}
switch (hdr.type) {
case MSG_CLIENT_TO_SERVER_EXEC_CMDLINE:
s_hdr.type = MSG_SERVER_TO_AGENT_EXEC_CMDLINE;
break;
case MSG_CLIENT_TO_SERVER_JUST_EXEC:
s_hdr.type = MSG_SERVER_TO_AGENT_JUST_EXEC;
break;
case MSG_CLIENT_TO_SERVER_CONNECT_EXISTING:
s_hdr.type = MSG_SERVER_TO_AGENT_CONNECT_EXISTING;
break;
default:
terminate_client_and_flush_data(fd);
return;
}
s_hdr.client_id = fd;
s_hdr.len = hdr.len;
if (!get_cmdline_body_from_client_and_pass_to_agent(fd, &s_hdr))
// client disconnected while sending cmdline, above call already
// cleaned up client info
return;
clients[fd].state = CLIENT_DATA;
set_nonblock(fd); // so that we can detect full queue without blocking
if (hdr.type == MSG_CLIENT_TO_SERVER_JUST_EXEC)
terminate_client_and_flush_data(fd);
}
/* handle data received from one of qrexec_client processes */
void handle_message_from_client(int fd)
{
struct server_header s_hdr;
char buf[MAX_DATA_CHUNK];
unsigned int len;
int ret;
if (clients[fd].state == CLIENT_CMDLINE) {
handle_cmdline_message_from_client(fd);
return;
}
// We have already passed cmdline from client.
// Now the client passes us raw data from its stdin.
len = buffer_space_vchan_ext();
if (len <= sizeof s_hdr)
return;
/* Read at most the amount of data that we have room for in vchan */
ret = read(fd, buf, len - sizeof(s_hdr));
if (ret < 0) {
perror("read client");
terminate_client_and_flush_data(fd);
return;
}
s_hdr.client_id = fd;
s_hdr.len = ret;
s_hdr.type = MSG_SERVER_TO_AGENT_INPUT;
write_all_vchan_ext(&s_hdr, sizeof(s_hdr));
write_all_vchan_ext(buf, ret);
if (ret == 0) // EOF - so don't select() on this client
clients[fd].state |= CLIENT_DONT_READ | CLIENT_EOF;
if (clients[fd].state & CLIENT_EXITED)
//client already exited and all data sent - cleanup now
terminate_client_and_flush_data(fd);
}
/*
Called when there is buffered data for this client, and select() reports
that client's pipe is writable; so we should be able to flush some
buffered data.
*/
void write_buffered_data_to_client(int client_id)
{
switch (flush_client_data
(client_id, client_id, &clients[client_id].buffer)) {
case WRITE_STDIN_OK: // no more buffered data
clients[client_id].state &= ~CLIENT_OUTQ_FULL;
break;
case WRITE_STDIN_ERROR:
// do not write to this fd anymore
clients[client_id].state |= CLIENT_EXITED;
if (clients[client_id].state & CLIENT_EOF)
terminate_client_and_flush_data(client_id);
else
// client will be removed when read returns 0 (EOF)
// clear CLIENT_OUTQ_FULL flag to no select on this fd anymore
clients[client_id].state &= ~CLIENT_OUTQ_FULL;
break;
case WRITE_STDIN_BUFFERED: // no room for all data, don't clear CLIENT_OUTQ_FULL flag
break;
default:
fprintf(stderr, "unknown flush_client_data?\n");
exit(1);
}
}
/*
The header (hdr argument) is already built. Just read the raw data from
the packet, and pass it along with the header to the client.
*/
void get_packet_data_from_agent_and_pass_to_client(int client_id, struct client_header
*hdr)
{
int len = hdr->len;
char buf[sizeof(*hdr) + len];
/* make both the header and data be consecutive in the buffer */
memcpy(buf, hdr, sizeof(*hdr));
read_all_vchan_ext(buf + sizeof(*hdr), len);
if (clients[client_id].state & CLIENT_EXITED)
// ignore data for no longer running client
return;
switch (write_stdin
(client_id, client_id, buf, len + sizeof(*hdr),
&clients[client_id].buffer)) {
case WRITE_STDIN_OK:
break;
case WRITE_STDIN_BUFFERED: // some data have been buffered
clients[client_id].state |= CLIENT_OUTQ_FULL;
break;
case WRITE_STDIN_ERROR:
// do not write to this fd anymore
clients[client_id].state |= CLIENT_EXITED;
// if already got EOF, remove client
if (clients[client_id].state & CLIENT_EOF)
terminate_client_and_flush_data(client_id);
break;
default:
fprintf(stderr, "unknown write_stdin?\n");
exit(1);
}
}
/*
The signal handler executes asynchronously; therefore all it should do is
to set a flag "signal has arrived", and let the main even loop react to this
flag in appropriate moment.
*/
int child_exited;
void sigchld_handler(int UNUSED(x))
{
child_exited = 1;
signal(SIGCHLD, sigchld_handler);
}
/* clean zombies, update children_count */
void reap_children(void)
{
int status;
while (waitpid(-1, &status, WNOHANG) > 0)
children_count--;
child_exited = 0;
}
/* too many children - wait for one of them to terminate */
void wait_for_child(void)
{
int status;
waitpid(-1, &status, 0);
children_count--;
}
#define MAX_CHILDREN 10
void check_children_count_and_wait_if_too_many(void)
{
if (children_count > MAX_CHILDREN) {
fprintf(stderr,
"max number of children reached, waiting for child exit...\n");
wait_for_child();
fprintf(stderr, "now children_count=%d, continuing.\n",
children_count);
}
}
void sanitize_name(char * untrusted_s_signed)
{
unsigned char * untrusted_s;
for (untrusted_s=(unsigned char*)untrusted_s_signed; *untrusted_s; untrusted_s++) {
if (*untrusted_s >= 'a' && *untrusted_s <= 'z')
continue;
if (*untrusted_s >= 'A' && *untrusted_s <= 'Z')
continue;
if (*untrusted_s >= '0' && *untrusted_s <= '9')
continue;
if (*untrusted_s == '$' || *untrusted_s == '_' || *untrusted_s == '-' || *untrusted_s == '.' || *untrusted_s == ' ')
continue;
*untrusted_s = '_';
}
}
#define ENSURE_NULL_TERMINATED(x) x[sizeof(x)-1] = 0
/*
Called when agent sends a message asking to execute a predefined command.
*/
void handle_execute_predefined_command(void)
{
int i;
struct trigger_connect_params untrusted_params, params;
check_children_count_and_wait_if_too_many();
read_all_vchan_ext(&untrusted_params, sizeof(params));
/* sanitize start */
ENSURE_NULL_TERMINATED(untrusted_params.exec_index);
ENSURE_NULL_TERMINATED(untrusted_params.target_vmname);
ENSURE_NULL_TERMINATED(untrusted_params.process_fds.ident);
sanitize_name(untrusted_params.exec_index);
sanitize_name(untrusted_params.target_vmname);
sanitize_name(untrusted_params.process_fds.ident);
params = untrusted_params;
/* sanitize end */
switch (fork()) {
case -1:
perror("fork");
exit(1);
case 0:
break;
default:
children_count++;
return;
}
for (i = 3; i < MAX_FDS; i++)
close(i);
signal(SIGCHLD, SIG_DFL);
signal(SIGPIPE, SIG_DFL);
execl("/usr/lib/qubes/qrexec-policy", "qrexec-policy", "--",
remote_domain_name, params.target_vmname,
params.exec_index, params.process_fds.ident, NULL);
perror("execl");
_exit(1);
}
void check_client_id_in_range(unsigned int untrusted_client_id)
{
if (untrusted_client_id >= MAX_CLIENTS) {
fprintf(stderr, "from agent: client_id=%d\n",
untrusted_client_id);
exit(1);
}
}
void sanitize_message_from_agent(struct server_header *untrusted_header)
{
switch (untrusted_header->type) {
case MSG_AGENT_TO_SERVER_TRIGGER_CONNECT_EXISTING:
break;
case MSG_AGENT_TO_SERVER_STDOUT:
case MSG_AGENT_TO_SERVER_STDERR:
case MSG_AGENT_TO_SERVER_EXIT_CODE:
check_client_id_in_range(untrusted_header->client_id);
if (untrusted_header->len > MAX_DATA_CHUNK) {
fprintf(stderr, "agent feeded %d of data bytes?\n",
untrusted_header->len);
exit(1);
}
break;
case MSG_XOFF:
case MSG_XON:
check_client_id_in_range(untrusted_header->client_id);
break;
default:
fprintf(stderr, "unknown mesage type %d from agent\n",
untrusted_header->type);
exit(1);
}
}
void handle_message_from_agent(void)
{
struct client_header hdr;
struct server_header s_hdr, untrusted_s_hdr;
read_all_vchan_ext(&untrusted_s_hdr, sizeof untrusted_s_hdr);
/* sanitize start */
sanitize_message_from_agent(&untrusted_s_hdr);
s_hdr = untrusted_s_hdr;
/* sanitize end */
// fprintf(stderr, "got %x %x %x\n", s_hdr.type, s_hdr.client_id,
// s_hdr.len);
if (s_hdr.type == MSG_AGENT_TO_SERVER_TRIGGER_CONNECT_EXISTING) {
handle_execute_predefined_command();
return;
}
if (s_hdr.type == MSG_XOFF) {
clients[s_hdr.client_id].state |= CLIENT_DONT_READ;
return;
}
if (s_hdr.type == MSG_XON) {
clients[s_hdr.client_id].state &= ~CLIENT_DONT_READ;
return;
}
switch (s_hdr.type) {
case MSG_AGENT_TO_SERVER_STDOUT:
hdr.type = MSG_SERVER_TO_CLIENT_STDOUT;
break;
case MSG_AGENT_TO_SERVER_STDERR:
hdr.type = MSG_SERVER_TO_CLIENT_STDERR;
break;
case MSG_AGENT_TO_SERVER_EXIT_CODE:
hdr.type = MSG_SERVER_TO_CLIENT_EXIT_CODE;
break;
default: /* cannot happen, already sanitized */
fprintf(stderr, "from agent: type=%d\n", s_hdr.type);
exit(1);
}
hdr.len = s_hdr.len;
if (clients[s_hdr.client_id].state == CLIENT_INVALID) {
// benefit of doubt - maybe client exited earlier
// just eat the packet data and continue
char buf[MAX_DATA_CHUNK];
read_all_vchan_ext(buf, s_hdr.len);
return;
}
get_packet_data_from_agent_and_pass_to_client(s_hdr.client_id,
&hdr);
if (s_hdr.type == MSG_AGENT_TO_SERVER_EXIT_CODE)
terminate_client_and_flush_data(s_hdr.client_id);
}
/*
Scan the "clients" table, add ones we want to read from (because the other
end has not send MSG_XOFF on them) to read_fdset, add ones we want to write
to (because its pipe is full) to write_fdset. Return the highest used file
descriptor number, needed for the first select() parameter.
*/
int fill_fdsets_for_select(fd_set * read_fdset, fd_set * write_fdset)
{
int i;
int max = -1;
FD_ZERO(read_fdset);
FD_ZERO(write_fdset);
for (i = 0; i <= max_client_fd; i++) {
if (clients[i].state != CLIENT_INVALID
&& !(clients[i].state & CLIENT_DONT_READ)) {
FD_SET(i, read_fdset);
max = i;
}
if (clients[i].state != CLIENT_INVALID
&& clients[i].state & CLIENT_OUTQ_FULL) {
FD_SET(i, write_fdset);
max = i;
}
}
FD_SET(qrexec_daemon_unix_socket_fd, read_fdset);
if (qrexec_daemon_unix_socket_fd > max)
max = qrexec_daemon_unix_socket_fd;
return max;
}
int main(int argc, char **argv)
{
fd_set read_fdset, write_fdset;
int i, opt;
int max;
sigset_t chld_set;
while ((opt=getopt(argc, argv, "q")) != -1) {
switch (opt) {
case 'q':
opt_quiet = 1;
break;
default: /* '?' */
fprintf(stderr, "usage: %s [-q] domainid domain-name [default user]\n", argv[0]);
exit(1);
}
}
if (argc - optind < 2 || argc - optind > 3) {
fprintf(stderr, "usage: %s [-q] domainid domain-name [default user]\n", argv[0]);
exit(1);
}
remote_domain_name = argv[optind+1];
if (argc - optind >= 3)
default_user = argv[optind+2];
remote_domain_xid = atoi(argv[optind]);
init(remote_domain_xid);
sigemptyset(&chld_set);
sigaddset(&chld_set, SIGCHLD);
/*
The main event loop. Waits for one of the following events:
- message from client
- message from agent
- new client
- child exited
*/
for (;;) {
max = fill_fdsets_for_select(&read_fdset, &write_fdset);
if (buffer_space_vchan_ext() <=
sizeof(struct server_header))
FD_ZERO(&read_fdset); // vchan full - don't read from clients
sigprocmask(SIG_BLOCK, &chld_set, NULL);
if (child_exited)
reap_children();
wait_for_vchan_or_argfd(max, &read_fdset, &write_fdset);
sigprocmask(SIG_UNBLOCK, &chld_set, NULL);
if (FD_ISSET(qrexec_daemon_unix_socket_fd, &read_fdset))
handle_new_client();
while (read_ready_vchan_ext())
handle_message_from_agent();
for (i = 0; i <= max_client_fd; i++)
if (clients[i].state != CLIENT_INVALID
&& FD_ISSET(i, &read_fdset))
handle_message_from_client(i);
for (i = 0; i <= max_client_fd; i++)
if (clients[i].state != CLIENT_INVALID
&& FD_ISSET(i, &write_fdset))
write_buffered_data_to_client(i);
}
}

217
qrexec/qrexec-policy Executable file
View File

@ -0,0 +1,217 @@
#!/usr/bin/python
import sys
import os
import os.path
import subprocess
import xen.lowlevel.xl
import qubes.guihelpers
from optparse import OptionParser
import fcntl
POLICY_FILE_DIR="/etc/qubes-rpc/policy"
# XXX: Backward compatibility, to be removed soon
DEPRECATED_POLICY_FILE_DIR="/etc/qubes_rpc/policy"
QREXEC_CLIENT="/usr/lib/qubes/qrexec-client"
class UserChoice:
ALLOW=0
DENY=1
ALWAYS_ALLOW=2
def line_to_dict(line):
tokens=line.split()
if len(tokens) < 3:
return None
if tokens[0][0] == '#':
return None
dict={}
dict['source']=tokens[0]
dict['dest']=tokens[1]
dict['full-action']=tokens[2]
action_list=tokens[2].split(',')
dict['action']=action_list.pop(0)
for iter in action_list:
paramval=iter.split("=")
dict["action."+paramval[0]]=paramval[1]
# Warn if we're ignoring extra data after a space, such as:
# vm1 vm2 allow, user=foo
if len(tokens) > 3:
print >>sys.stderr, "Trailing data ignored in %s" % line
return dict
def read_policy_file(exec_index):
policy_file=POLICY_FILE_DIR+"/"+exec_index
if not os.path.isfile(policy_file):
policy_file=DEPRECATED_POLICY_FILE_DIR+"/"+exec_index
if not os.path.isfile(policy_file):
return None
print >>sys.stderr, "RPC service '%s' uses deprecated policy location, please move to %s" % (exec_index, POLICY_FILE_DIR)
policy_list=list()
f = open(policy_file)
fcntl.flock(f, fcntl.LOCK_SH)
for iter in f.readlines():
dict = line_to_dict(iter)
if dict is not None:
policy_list.append(dict)
f.close()
return policy_list
def is_match(item, config_term):
return (item is not "dom0" and config_term == "$anyvm") or item == config_term
def get_default_policy():
dict={}
dict["action"]="deny"
return dict
def find_policy(policy, domain, target):
for iter in policy:
if not is_match(domain, iter["source"]):
continue
if not is_match(target, iter["dest"]):
continue
return iter
return get_default_policy()
def is_domain_running(target):
xl_ctx = xen.lowlevel.xl.ctx()
domains = xl_ctx.list_domains()
for dominfo in domains:
domname = xl_ctx.domid_to_name(dominfo.domid)
if domname == target:
return True
return False
def validate_target(target):
# special targets
if target in ['$dispvm', 'dom0']:
return True
from qubes.qubes import QubesVmCollection
qc = QubesVmCollection()
qc.lock_db_for_reading()
qc.load()
qc.unlock_db()
return qc.get_vm_by_name(target) is not None
def spawn_target_if_necessary(target):
if is_domain_running(target):
return
null=open("/dev/null", "r+")
subprocess.call(["qvm-run", "-a", "-q", target, "true"], stdin=null, stdout=null)
null.close()
def do_execute(domain, target, user, exec_index, process_ident):
if target == "dom0":
cmd="/usr/lib/qubes/qubes-rpc-multiplexer "+exec_index + " " + domain
elif target == "$dispvm":
cmd = "/usr/lib/qubes/qfile-daemon-dvm " + exec_index + " " + domain + " " +user
else:
# see the previous commit why "qvm-run -a" is broken and dangerous
# also, dangling "xl" would keep stderr open and may prevent closing connection
spawn_target_if_necessary(target)
cmd= QREXEC_CLIENT + " -d " + target + " '" + user
cmd+=":QUBESRPC "+ exec_index + " " + domain + "'"
# stderr should be logged in source/target VM
null = open(os.devnull, 'w')
os.dup2(null.fileno(), 2)
os.execl(QREXEC_CLIENT, "qrexec-client", "-d", domain, "-l", cmd, "-c", process_ident)
def confirm_execution(domain, target, exec_index):
text = "Do you allow domain \"" +domain + "\" to execute " + exec_index
text+= " operation on the domain \"" + target +"\"?<br>"
text+= " \"Yes to All\" option will automatically allow this operation in the future."
return qubes.guihelpers.ask(text, yestoall=True)
def add_always_allow(domain, target, exec_index, options):
policy_file=POLICY_FILE_DIR+"/"+exec_index
if not os.path.isfile(policy_file):
return None
f = open(policy_file, 'r+')
fcntl.flock(f, fcntl.LOCK_EX)
lines = []
for l in f.readlines():
lines.append(l)
lines.insert(0, "%s\t%s\tallow%s\n" % (domain, target, options))
f.seek(0)
f.write("".join(lines))
f.close()
def policy_editor(domain, target, exec_index):
text = "No policy definition found for " + exec_index + " action. "
text+= "Please create a policy file in Dom0 in " + POLICY_FILE_DIR + "/" + exec_index
subprocess.call(["/usr/bin/zenity", "--info", "--text", text])
def main():
usage = "usage: %prog [options] <src-domain> <target-domain> <service> <process-ident>"
parser = OptionParser (usage)
parser.add_option ("--assume-yes-for-ask", action="store_true", dest="assume_yes_for_ask", default=False,
help="Allow run of service without confirmation if policy say 'ask'")
parser.add_option ("--just-evaluate", action="store_true", dest="just_evaluate", default=False,
help="Do not run the service, only evaluate policy; retcode=0 means 'allow'")
(options, args) = parser.parse_args ()
domain=args[0]
target=args[1]
exec_index=args[2]
process_ident=args[3]
if not validate_target(target):
print >> sys.stderr, "Rpc failed (unknown domain):", domain, target, exec_index
text = "Domain '%s' doesn't exist (service %s called by domain %s)." % (
target, exec_index, domain)
subprocess.call(["/usr/bin/zenity", "--error", "--text", text])
os.execl(QREXEC_CLIENT, "qrexec-client", "-d", domain, "-l", "/bin/false", "-c", process_ident)
policy_list=read_policy_file(exec_index)
if policy_list==None:
policy_editor(domain, target, exec_index)
policy_list=read_policy_file(exec_index)
if policy_list==None:
policy_list=list()
policy_dict=find_policy(policy_list, domain, target)
if policy_dict["action"] == "ask" and options.assume_yes_for_ask:
policy_dict["action"] = "allow"
if policy_dict["action"] == "ask":
user_choice = confirm_execution(domain, target, exec_index)
if user_choice == UserChoice.ALWAYS_ALLOW:
add_always_allow(domain, target, exec_index, policy_dict["full-action"].lstrip('ask'))
policy_dict["action"] = "allow"
elif user_choice == UserChoice.ALLOW:
policy_dict["action"] = "allow"
else:
policy_dict["action"] = "deny"
if options.just_evaluate:
if policy_dict["action"] == "allow":
exit(0)
else:
exit(1)
if policy_dict["action"] == "allow":
if policy_dict.has_key("action.target"):
target=policy_dict["action.target"]
if policy_dict.has_key("action.user"):
user=policy_dict["action.user"]
else:
user="DEFAULT"
print >> sys.stderr, "Rpc allowed:", domain, target, exec_index
do_execute(domain, target, user, exec_index, process_ident)
print >> sys.stderr, "Rpc denied:", domain, target, exec_index
os.execl(QREXEC_CLIENT, "qrexec-client", "-d", domain, "-l", "/bin/false", "-c", process_ident)
main()

30
qrexec/qubes-rpc-multiplexer Executable file
View File

@ -0,0 +1,30 @@
#!/bin/sh
mkfifo /tmp/qrexec-rpc-stderr.$$
logger -t "$1-$2" -f /tmp/qrexec-rpc-stderr.$$ &
exec 2>/tmp/qrexec-rpc-stderr.$$
rm -f /tmp/qrexec-rpc-stderr.$$
QUBES_RPC=/etc/qubes-rpc
# XXX: Backward compatibility
DEPRECATED_QUBES_RPC=/etc/qubes_rpc
if ! [ $# = 2 ] ; then
echo $0: bad argument count >&2
exit 1
fi
export QREXEC_REMOTE_DOMAIN="$2"
CFG_FILE=$QUBES_RPC/"$1"
if [ -s "$CFG_FILE" ] ; then
exec /bin/sh "$CFG_FILE"
echo "$0: failed to execute handler for" "$1" >&2
exit 1
fi
CFG_FILE=$DEPRECATED_QUBES_RPC/"$1"
if [ -s "$CFG_FILE" ] ; then
echo "$0: RPC service '$1' uses deprecated directory, please move to $QUBES_RPC" >&2
exec /bin/sh "$CFG_FILE"
echo "$0: failed to execute handler for" "$1" >&2
exit 1
fi
echo "$0: nonexistent or empty" "$CFG_FILE" file >&2
exit 1

View File

@ -1,7 +0,0 @@
## Note that policy parsing stops at the first match,
## so adding anything below "$anyvm $anyvm action" line will have no effect
## Please use a single # to start your custom comments
dom0 dom0 allow
$anyvm $anyvm deny

View File

@ -1,7 +0,0 @@
## Note that policy parsing stops at the first match,
## so adding anything below "$anyvm $anyvm action" line will have no effect
## Please use a single # to start your custom comments
dom0 dom0 allow
$anyvm $anyvm deny

View File

@ -1,7 +0,0 @@
## Note that policy parsing stops at the first match,
## so adding anything below "$anyvm $anyvm action" line will have no effect
## Please use a single # to start your custom comments
dom0 dom0 allow
$anyvm $anyvm deny

View File

@ -1,24 +0,0 @@
#!/usr/bin/python3
# `ok` on stdout indicates success; any stderr output indicates an error
# (probably an exception)
import dnf
import os
import sys
os.umask(0o022)
base = dnf.Base()
base.read_all_repos()
reponame = sys.argv[1]
repo = base.repos[reponame]
base.conf.write_raw_configfile(repo.repofile,
repo.id,
base.conf.substitutions,
{'enabled': '0'})
print('ok')

View File

@ -1,24 +0,0 @@
#!/usr/bin/python3
# `ok` on stdout indicates success; any stderr output indicates an error
# (probably an exception)
import dnf
import os
import sys
os.umask(0o022)
base = dnf.Base()
base.read_all_repos()
reponame = sys.argv[1]
repo = base.repos[reponame]
base.conf.write_raw_configfile(repo.repofile,
repo.id,
base.conf.substitutions,
{'enabled': '1'})
print('ok')

View File

@ -1,17 +0,0 @@
#!/usr/bin/python3
# Records in the output are separated by newlines; fields are separated by \0
# Each record is unique_id:pretty_name:enabled
import dnf
base = dnf.Base()
base.read_all_repos()
first = True
for repo in base.repos.all():
l = [repo.id, repo.name, 'enabled' if repo.enabled else 'disabled']
if not first: print()
first = False
print('\0'.join(l), end='')

View File

@ -24,10 +24,15 @@
%{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
%{!?version: %define version %(cat version)}
%define _dracutmoddir /usr/lib/dracut/modules.d
%if %{fedora} < 17
%define _dracutmoddir /usr/share/dracut/modules.d
%endif
Name: qubes-core-dom0-linux
Version: @VERSION@
Version: %{version}
Release: 1%{?dist}
Summary: Linux-specific files for Qubes dom0
@ -38,20 +43,12 @@ URL: http://www.qubes-os.org
BuildRequires: ImageMagick
BuildRequires: pandoc
BuildRequires: qubes-utils-devel >= 3.1.3
BuildRequires: gcc
BuildRequires: qubes-utils-devel >= 2.0.5
Requires: qubes-core-dom0
Requires: python3-qubesadmin
Requires: qubes-core-qrexec-dom0
Requires: qubes-core-admin-client
Requires: qubes-utils >= 3.1.3
Requires: qubes-utils-libs >= 4.0.16
Conflicts: qubes-core-dom0 < 4.0.23
Requires: qubes-utils >= 2.0.6
Requires: %{name}-kernel-install
Requires: xdotool
Requires: createrepo_c
Source0: %{name}-%{version}.tar.gz
%define _builddir %(pwd)
%description
Linux customizations required to use system as Qubes dom0.
@ -70,25 +67,45 @@ Obsoletes: os-prober
Kernel install hook for Xen-based system.
%prep
%setup -q
# we operate on the current directory, so no need to unpack anything
# symlink is to generate useful debuginfo packages
rm -f %{name}-%{version}
ln -sf . %{name}-%{version}
%setup -T -D
%build
export BACKEND_VMM=@BACKEND_VMM@
python -m compileall appmenus-scripts
python -O -m compileall appmenus-scripts
(cd dom0-updates; make)
(cd file-copy-vm; make)
(cd qrexec; make)
(cd doc; make manpages)
%install
## Appmenus
install -d $RPM_BUILD_ROOT/etc/qubes-rpc/policy
cp qubesappmenus/qubes.SyncAppMenus.policy $RPM_BUILD_ROOT/etc/qubes-rpc/policy/qubes.SyncAppMenus
### Appmenus
mkdir -p $RPM_BUILD_ROOT%{python_sitearch}/qubes/modules
cp appmenus-scripts/qubes-core-appmenus.py $RPM_BUILD_ROOT%{python_sitearch}/qubes/modules/10appmenus.py
cp appmenus-scripts/qubes-core-appmenus.pyc $RPM_BUILD_ROOT%{python_sitearch}/qubes/modules/10appmenus.pyc
cp appmenus-scripts/qubes-core-appmenus.pyo $RPM_BUILD_ROOT%{python_sitearch}/qubes/modules/10appmenus.pyo
mkdir -p $RPM_BUILD_ROOT/usr/libexec/qubes-appmenus
cp appmenus-scripts/*.sh $RPM_BUILD_ROOT/usr/libexec/qubes-appmenus/
cp appmenus-scripts/qubes-receive-appmenus $RPM_BUILD_ROOT/usr/libexec/qubes-appmenus/
install -D appmenus-scripts/qvm-sync-appmenus $RPM_BUILD_ROOT/usr/bin/qvm-sync-appmenus
mkdir -p $RPM_BUILD_ROOT/etc/qubes-rpc/policy
cp appmenus-scripts/qubes.SyncAppMenus $RPM_BUILD_ROOT/etc/qubes-rpc/
cp appmenus-scripts/qubes.SyncAppMenus.policy $RPM_BUILD_ROOT/etc/qubes-rpc/policy/qubes.SyncAppMenus
mkdir -p $RPM_BUILD_ROOT/usr/share/qubes-appmenus/
cp -r appmenus-files/* $RPM_BUILD_ROOT/usr/share/qubes-appmenus/
### Dom0 updates
install -D dom0-updates/qubes-dom0-updates.cron $RPM_BUILD_ROOT/etc/cron.daily/qubes-dom0-updates.cron
install -D dom0-updates/qubes-dom0-update $RPM_BUILD_ROOT/usr/bin/qubes-dom0-update
install -D dom0-updates/qubes-receive-updates $RPM_BUILD_ROOT/usr/libexec/qubes/qubes-receive-updates
install -D dom0-updates/patch-dnf-yum-config $RPM_BUILD_ROOT/usr/lib/qubes/patch-dnf-yum-config
install -m 0644 -D dom0-updates/qubes-cached.repo $RPM_BUILD_ROOT/etc/yum.real.repos.d/qubes-cached.repo
install -D dom0-updates/qfile-dom0-unpacker $RPM_BUILD_ROOT/usr/libexec/qubes/qfile-dom0-unpacker
install -m 0644 -D dom0-updates/qubes.ReceiveUpdates $RPM_BUILD_ROOT/etc/qubes-rpc/qubes.ReceiveUpdates
@ -96,14 +113,19 @@ install -m 0664 -D dom0-updates/qubes.ReceiveUpdates.policy $RPM_BUILD_ROOT/etc/
install -d $RPM_BUILD_ROOT/var/lib/qubes/updates
# Qrexec services
mkdir -p $RPM_BUILD_ROOT/usr/lib/qubes/qubes-rpc $RPM_BUILD_ROOT/etc/qubes-rpc/policy
cp qubes-rpc/* $RPM_BUILD_ROOT/usr/lib/qubes/qubes-rpc/
for i in qubes-rpc/*; do ln -s ../../usr/lib/qubes/$i $RPM_BUILD_ROOT/etc/qubes-rpc/$(basename $i); done
cp qubes-rpc-policy/* $RPM_BUILD_ROOT/etc/qubes-rpc/policy/
# Qrexec
mkdir -p $RPM_BUILD_ROOT/usr/lib/qubes/
cp qrexec/qrexec-daemon $RPM_BUILD_ROOT/usr/lib/qubes/
cp qrexec/qrexec-client $RPM_BUILD_ROOT/usr/lib/qubes/
# XXX: Backward compatibility
ln -s qrexec-client $RPM_BUILD_ROOT/usr/lib/qubes/qrexec_client
cp qrexec/qrexec-policy $RPM_BUILD_ROOT/usr/lib/qubes/
cp qrexec/qubes-rpc-multiplexer $RPM_BUILD_ROOT/usr/lib/qubes
### pm-utils
mkdir -p $RPM_BUILD_ROOT/usr/lib64/pm-utils/sleep.d
cp pm-utils/01qubes-sync-vms-clock $RPM_BUILD_ROOT/usr/lib64/pm-utils/sleep.d/
cp pm-utils/51qubes-suspend-netvm $RPM_BUILD_ROOT/usr/lib64/pm-utils/sleep.d/
cp pm-utils/52qubes-pause-vms $RPM_BUILD_ROOT/usr/lib64/pm-utils/sleep.d/
mkdir -p $RPM_BUILD_ROOT/usr/lib/systemd/system
cp pm-utils/qubes-suspend.service $RPM_BUILD_ROOT/usr/lib/systemd/system/
@ -119,37 +141,23 @@ cp -r dracut/modules.d/* $RPM_BUILD_ROOT%{_dracutmoddir}/
mkdir -p $RPM_BUILD_ROOT/etc/sysconfig
install -m 0644 -D system-config/limits-qubes.conf $RPM_BUILD_ROOT/etc/security/limits.d/99-qubes.conf
install -D system-config/cpufreq-xen.modules $RPM_BUILD_ROOT/etc/sysconfig/modules/cpufreq-xen.modules
cp system-config/iptables $RPM_BUILD_ROOT/etc/sysconfig
cp system-config/ip6tables $RPM_BUILD_ROOT/etc/sysconfig
install -m 0440 -D system-config/qubes.sudoers $RPM_BUILD_ROOT/etc/sudoers.d/qubes
install -D system-config/polkit-1-qubes-allow-all.rules $RPM_BUILD_ROOT/etc/polkit-1/rules.d/00-qubes-allow-all.rules
install -D system-config/qubes-dom0.modules $RPM_BUILD_ROOT/etc/sysconfig/modules/qubes-dom0.modules
install -D system-config/qubes-sync-clock.cron $RPM_BUILD_ROOT/etc/cron.d/qubes-sync-clock.cron
install -D system-config/lvm-cleanup.cron-daily $RPM_BUILD_ROOT/etc/cron.daily/lvm-cleanup
install -d $RPM_BUILD_ROOT/etc/udev/rules.d
install -m 644 system-config/00-qubes-ignore-devices.rules $RPM_BUILD_ROOT/etc/udev/rules.d/
install -m 644 system-config/12-qubes-ignore-lvm-devices.rules $RPM_BUILD_ROOT/etc/udev/rules.d/
install -m 644 -D system-config/disable-lesspipe.sh $RPM_BUILD_ROOT/etc/profile.d/zz-disable-lesspipe.sh
install -m 755 -D system-config/kernel-grub2.install $RPM_BUILD_ROOT/usr/lib/kernel/install.d/80-grub2.install
install -m 755 -D system-config/kernel-xen-efi.install $RPM_BUILD_ROOT/usr/lib/kernel/install.d/90-xen-efi.install
install -m 755 -D system-config/kernel-remove-bls.install $RPM_BUILD_ROOT/usr/lib/kernel/install.d/99-remove-bls.install
install -m 644 -D system-config/75-qubes-dom0.preset \
$RPM_BUILD_ROOT/usr/lib/systemd/system-preset/75-qubes-dom0.preset
install -m 644 -D system-config/75-qubes-dom0-user.preset \
$RPM_BUILD_ROOT/usr/lib/systemd/user-preset/75-qubes-dom0-user.preset
install -m 644 -D system-config/99-qubes-default-disable.preset \
$RPM_BUILD_ROOT/usr/lib/systemd/system-preset/99-qubes-default-disable.preset
install -d $RPM_BUILD_ROOT/etc/dnf/protected.d
install -m 0644 system-config/dnf-protected-qubes-core-dom0.conf \
$RPM_BUILD_ROOT/etc/dnf/protected.d/qubes-core-dom0.conf
install -m 644 system-config/60-persistent-storage.rules $RPM_BUILD_ROOT/etc/udev/rules.d/
install -m 644 -D system-config/disable-lesspipe $RPM_BUILD_ROOT/etc/profile.d/zz-disable-lesspipe
install -m 755 -D system-config/kernel-grub2.install $RPM_BUILD_ROOT/usr/lib/kernel/install.d/90-grub2.install
touch $RPM_BUILD_ROOT/var/lib/qubes/.qubes-exclude-block-devices
# file copy to VM
install -m 755 file-copy-vm/qfile-dom0-agent $RPM_BUILD_ROOT/usr/lib/qubes/
install -m 755 file-copy-vm/qvm-copy-to-vm $RPM_BUILD_ROOT/usr/bin/
install -m 755 file-copy-vm/qvm-copy $RPM_BUILD_ROOT/usr/bin/
ln -s qvm-copy-to-vm $RPM_BUILD_ROOT/usr/bin/qvm-move-to-vm
ln -s qvm-copy $RPM_BUILD_ROOT/usr/bin/qvm-move
### Icons
mkdir -p $RPM_BUILD_ROOT/usr/share/qubes/icons
for icon in icons/*.png; do
convert -resize 48 $icon $RPM_BUILD_ROOT/usr/share/qubes/$icon
done
### Documentation
(cd doc; make DESTDIR=$RPM_BUILD_ROOT install)
@ -161,22 +169,34 @@ fi
%post
/usr/lib/qubes/patch-dnf-yum-config
for i in /usr/share/qubes/icons/*.png ; do
xdg-icon-resource install --noupdate --novendor --size 48 $i
done
xdg-icon-resource forceupdate
xdg-desktop-menu install /usr/share/qubes-appmenus/qubes-dispvm.directory /usr/share/qubes-appmenus/qubes-dispvm-firefox.desktop
sed '/^reposdir\s*=/d' -i /etc/yum.conf
echo reposdir=/etc/yum.real.repos.d >> /etc/yum.conf
sed '/^installonlypkgs\s*=/d' -i /etc/yum.conf
echo 'installonlypkgs = kernel, kernel-qubes-vm' >> /etc/yum.conf
sed '/^distroverpkg\s*=/d' -i /etc/yum.conf
echo 'distroverpkg = qubes-release' >> /etc/yum.conf
systemctl enable qubes-suspend.service >/dev/null 2>&1
# migrate dom0-updates check disable flag
if [ $1 -ge 2 ]; then
if [ -e /var/lib/qubes/updates/disable-updates ]; then
qvm-features dom0 service.qubes-update-check ''
rm -f /var/lib/qubes/updates/disable-updates
fi
fi
%preun
if [ "$1" = 0 ] ; then
# no more packages left
for i in /usr/share/qubes/icons/*.png ; do
xdg-icon-resource uninstall --novendor --size 48 $i
done
xdg-desktop-menu uninstall /usr/share/qubes-appmenus/qubes-dispvm.directory /usr/share/qubes-appmenus/qubes-dispvm-firefox.desktop
systemctl disable qubes-suspend.service > /dev/null 2>&1
fi
@ -192,64 +212,71 @@ rm -f /lib/udev/rules.d/69-xorg-vmmouse.rules
chmod -x /etc/grub.d/10_linux
%files
%attr(2775,root,qubes) %dir /etc/qubes-rpc
%attr(2775,root,qubes) %dir /etc/qubes-rpc/policy
/etc/qubes-rpc/policy/qubes.SyncAppMenus
/etc/qubes-rpc/qubes.SyncAppMenus
%{python_sitearch}/qubes/modules/10appmenus.py
%{python_sitearch}/qubes/modules/10appmenus.pyc
%{python_sitearch}/qubes/modules/10appmenus.pyo
/usr/libexec/qubes-appmenus/convert-apptemplate2vm.sh
/usr/libexec/qubes-appmenus/convert-dirtemplate2vm.sh
/usr/libexec/qubes-appmenus/create-apps-for-appvm.sh
/usr/libexec/qubes-appmenus/qubes-receive-appmenus
/usr/libexec/qubes-appmenus/remove-appvm-appmenus.sh
/usr/share/qubes-appmenus/qubes-appmenu-select.desktop
/usr/share/qubes-appmenus/qubes-dispvm-firefox.desktop
/usr/share/qubes-appmenus/qubes-dispvm.directory
/usr/share/qubes-appmenus/qubes-servicevm.directory.template
/usr/share/qubes-appmenus/qubes-start.desktop
/usr/share/qubes-appmenus/qubes-templatevm.directory.template
/usr/share/qubes-appmenus/qubes-vm.directory.template
/usr/share/qubes-appmenus/hvm
/usr/share/qubes/icons/*.png
/usr/bin/qvm-sync-appmenus
# Dom0 updates
/etc/cron.daily/qubes-dom0-updates.cron
/etc/yum.real.repos.d/qubes-cached.repo
/usr/bin/qubes-dom0-update
/usr/lib/qubes/patch-dnf-yum-config
%attr(4750,root,qubes) /usr/libexec/qubes/qfile-dom0-unpacker
/usr/libexec/qubes/qubes-receive-updates
/etc/qubes-rpc/qubes.ReceiveUpdates
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.ReceiveUpdates
%attr(0770,root,qubes) %dir /var/lib/qubes/updates
# Qrexec services
/etc/qubes-rpc/qubes.repos.*
/usr/lib/qubes/qubes-rpc/qubes.repos.*
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.repos.List
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.repos.Enable
%attr(0664,root,qubes) %config(noreplace) /etc/qubes-rpc/policy/qubes.repos.Disable
# Dracut module
/etc/dracut.conf.d/*
%dir %{_dracutmoddir}/90macbook12-spi-driver
%{_dracutmoddir}/90macbook12-spi-driver/*
%dir %{_dracutmoddir}/90qubes-pciback
%{_dracutmoddir}/90qubes-pciback/*
%dir %{_dracutmoddir}/90extra-modules
%{_dracutmoddir}/90extra-modules/*
# file copy
/usr/bin/qvm-copy-to-vm
/usr/bin/qvm-move-to-vm
/usr/bin/qvm-copy
/usr/bin/qvm-move
/usr/lib/qubes/qfile-dom0-agent
# Qrexec
%attr(4750,root,qubes) /usr/lib/qubes/qrexec-daemon
/usr/lib/qubes/qrexec-client
/usr/lib/qubes/qrexec_client
/usr/lib/qubes/qubes-rpc-multiplexer
/usr/lib/qubes/qrexec-policy
# pm-utils
/usr/lib64/pm-utils/sleep.d/01qubes-sync-vms-clock
/usr/lib64/pm-utils/sleep.d/51qubes-suspend-netvm
/usr/lib64/pm-utils/sleep.d/52qubes-pause-vms
/usr/lib/systemd/system/qubes-suspend.service
# Others
/etc/sysconfig/iptables
/etc/sysconfig/ip6tables
/etc/sysconfig/modules/qubes-dom0.modules
/etc/sysconfig/modules/cpufreq-xen.modules
/etc/sudoers.d/qubes
/etc/polkit-1/rules.d/00-qubes-allow-all.rules
/etc/security/limits.d/99-qubes.conf
%config /etc/udev/rules.d/00-qubes-ignore-devices.rules
%config /etc/udev/rules.d/12-qubes-ignore-lvm-devices.rules
%config(noreplace) /etc/udev/rules.d/60-persistent-storage.rules
%attr(0644,root,root) /etc/cron.d/qubes-sync-clock.cron
/etc/cron.daily/lvm-cleanup
%config(noreplace) /etc/profile.d/zz-disable-lesspipe.sh
%config(noreplace) /etc/dnf/protected.d/qubes-core-dom0.conf
/usr/lib/systemd/system-preset/75-qubes-dom0.preset
/usr/lib/systemd/system-preset/99-qubes-default-disable.preset
/usr/lib/systemd/user-preset/75-qubes-dom0-user.preset
/var/lib/qubes/.qubes-exclude-block-devices
%config(noreplace) /etc/profile.d/zz-disable-lesspipe
# Man
%{_mandir}/man1/qvm-*.1*
%{_mandir}/man1/qubes-*.1*
%files kernel-install
/usr/lib/kernel/install.d/80-grub2.install
/usr/lib/kernel/install.d/90-xen-efi.install
/usr/lib/kernel/install.d/99-remove-bls.install
/usr/lib/kernel/install.d/90-grub2.install
%changelog
@CHANGELOG@

View File

@ -1,5 +1,7 @@
%{!?version: %define version %(cat version_vaio_fixes)}
Name: qubes-core-dom0-vaio-fixes
Version: @VERSION1@
Version: %{version}
Release: 1%{?dist}
Summary: Additional scripts for supporting suspend on Vaio Z laptops
Requires: alsa-utils
@ -9,7 +11,7 @@ Vendor: Invisible Things Lab
License: GPL
URL: http://www.qubes-os.org
Source0: qubes-core-dom0-linux-@VERSION@.tar.gz
%define _builddir %(pwd)
%description
Additional scripts for supporting suspend on Vaio Z laptops.
@ -17,20 +19,14 @@ Additional scripts for supporting suspend on Vaio Z laptops.
Due to broken Linux GPU drivers we need to do some additional actions during
suspend/resume.
%prep
%setup -q -n qubes-core-dom0-linux-@VERSION@
%install
mkdir -p $RPM_BUILD_ROOT/usr/lib64/pm-utils/sleep.d
install -D vaio-fixes/00sony-vaio-audio $RPM_BUILD_ROOT/usr/lib64/pm-utils/sleep.d/
install -D vaio-fixes/99sony-vaio-audio $RPM_BUILD_ROOT/usr/lib64/pm-utils/sleep.d/
cp vaio-fixes/00sony-vaio-audio $RPM_BUILD_ROOT/usr/lib64/pm-utils/sleep.d/
cp vaio-fixes/99sony-vaio-audio $RPM_BUILD_ROOT/usr/lib64/pm-utils/sleep.d/
mkdir -p $RPM_BUILD_ROOT/etc/modprobe.d/
install -D vaio-fixes/snd-hda-intel-sony-vaio.conf $RPM_BUILD_ROOT/etc/modprobe.d/
cp vaio-fixes/snd-hda-intel-sony-vaio.conf $RPM_BUILD_ROOT/etc/modprobe.d/
%files
/usr/lib64/pm-utils/sleep.d/00sony-vaio-audio
/usr/lib64/pm-utils/sleep.d/99sony-vaio-audio
/etc/modprobe.d/snd-hda-intel-sony-vaio.conf
%changelog
@CHANGELOG@

View File

@ -1,11 +1,6 @@
# do not edit this file, it will be overwritten on update
ACTION!="remove", SUBSYSTEM=="block", KERNEL=="loop*", ATTR{loop/backing_file}=="*/appvms/*/*.img*|*/vm-templates/*/*.img*", ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}="1", ENV{UDEV_DISABLE_PERSISTENT_STORAGE_RULES_FLAG}="1"
ACTION!="remove", SUBSYSTEM=="block", KERNEL=="xvd*", ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}="1", ENV{UDEV_DISABLE_PERSISTENT_STORAGE_RULES_FLAG}="1"
ACTION!="remove", SUBSYSTEM=="block", KERNEL=="loop*", ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}="1"
# ENV{DM_NAME} not available yet
# Template VM disks
ACTION!="remove", SUBSYSTEM=="block", ATTR{dm/name}=="snapshot-*", ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}="1"
ACTION!="remove", SUBSYSTEM=="block", ATTR{dm/name}=="origin-*", ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}="1"
# kpartx used for creating empty volatile.img, udevd tries to access the device
# and prevent kpartx from removing them
ACTION!="remove", SUBSYSTEM=="block", ATTR{dm/name}=="loop*p*", ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}="1"

View File

@ -1,4 +0,0 @@
# do not edit this file, it will be overwritten on update
# Skip VM images managed by lvm storage pool
ACTION!="remove", SUBSYSTEM=="block", ENV{DM_LV_NAME}=="vm-*", ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}="1", ENV{UDEV_DISABLE_PERSISTENT_STORAGE_RULES_FLAG}="1"

View File

@ -0,0 +1,87 @@
# do not edit this file, it will be overwritten on update
# persistent storage links: /dev/disk/{by-id,by-uuid,by-label,by-path}
# scheme based on "Linux persistent device names", 2004, Hannes Reinecke <hare@suse.de>
# forward scsi device event to corresponding block device
ACTION=="change", SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST=="block", ATTR{block/*/uevent}="change"
ACTION=="remove", GOTO="persistent_storage_end"
# enable in-kernel media-presence polling
ACTION=="add", SUBSYSTEM=="module", KERNEL=="block", ATTR{parameters/events_dfl_poll_msecs}=="0", ATTR{parameters/events_dfl_poll_msecs}="2000"
SUBSYSTEM!="block", GOTO="persistent_storage_end"
# skip rules for inappropriate block devices
KERNEL=="loop*|fd*|mtd*|nbd*|gnbd*|btibm*|dm-*|md*|zram*", GOTO="persistent_storage_end"
# ignore partitions that span the entire disk
TEST=="whole_disk", GOTO="persistent_storage_end"
# for partitions import parent information
ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_*"
# virtio-blk
KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}"
KERNEL=="vd*[0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}-part%n"
# ATA devices using the "scsi" subsystem
KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", IMPORT{program}="ata_id --export $devnode"
# ATA/ATAPI devices (SPC-3 or later) using the "scsi" subsystem
KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", ATTRS{type}=="5", ATTRS{scsi_level}=="[6-9]*", IMPORT{program}="ata_id --export $devnode"
# Run ata_id on non-removable USB Mass Storage (SATA/PATA disks in enclosures)
KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", ATTR{removable}=="0", SUBSYSTEMS=="usb", IMPORT{program}="ata_id --export $devnode"
# Otherwise, fall back to using usb_id for USB devices
KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
# scsi devices
KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --whitelisted -d $devnode", ENV{ID_BUS}="scsi"
KERNEL=="cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --whitelisted -d $devnode", ENV{ID_BUS}="cciss"
KERNEL=="sd*|sr*|cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}"
KERNEL=="sd*|cciss*", ENV{DEVTYPE}=="partition", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}-part%n"
# firewire
KERNEL=="sd*[!0-9]|sr*", ATTRS{ieee1394_id}=="?*", SYMLINK+="disk/by-id/ieee1394-$attr{ieee1394_id}"
KERNEL=="sd*[0-9]", ATTRS{ieee1394_id}=="?*", SYMLINK+="disk/by-id/ieee1394-$attr{ieee1394_id}-part%n"
KERNEL=="mmcblk[0-9]", SUBSYSTEMS=="mmc", ATTRS{name}=="?*", ATTRS{serial}=="?*", ENV{ID_NAME}="$attr{name}", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/mmc-$env{ID_NAME}_$env{ID_SERIAL}"
KERNEL=="mmcblk[0-9]p[0-9]", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/mmc-$env{ID_NAME}_$env{ID_SERIAL}-part%n"
KERNEL=="mspblk[0-9]", SUBSYSTEMS=="memstick", ATTRS{name}=="?*", ATTRS{serial}=="?*", ENV{ID_NAME}="$attr{name}", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/memstick-$env{ID_NAME}_$env{ID_SERIAL}"
KERNEL=="mspblk[0-9]p[0-9]", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/memstick-$env{ID_NAME}_$env{ID_SERIAL}-part%n"
# by-path (parent device path)
ENV{DEVTYPE}=="disk", DEVPATH!="*/virtual/*", IMPORT{builtin}="path_id"
ENV{DEVTYPE}=="disk", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}"
ENV{DEVTYPE}=="partition", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}-part%n"
# skip unpartitioned removable media devices from drivers which do not send "change" events
ENV{DEVTYPE}=="disk", KERNEL!="sd*|sr*", ATTR{removable}=="1", GOTO="persistent_storage_end"
# probe filesystem metadata of optical drives which have a media inserted
KERNEL=="sr*", ENV{DISK_EJECT_REQUEST}!="?*", ENV{ID_CDROM_MEDIA_TRACK_COUNT_DATA}=="?*", ENV{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}=="?*", \
IMPORT{builtin}="blkid --offset=$env{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}"
# single-session CDs do not have ID_CDROM_MEDIA_SESSION_LAST_OFFSET
KERNEL=="sr*", ENV{DISK_EJECT_REQUEST}!="?*", ENV{ID_CDROM_MEDIA_TRACK_COUNT_DATA}=="?*", ENV{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}=="", \
IMPORT{builtin}="blkid --noraid"
# probe filesystem metadata of disks
KERNEL!="sr*", IMPORT{builtin}="blkid"
# watch metadata changes by tools closing the device after writing
KERNEL!="sr*", OPTIONS+="watch"
# by-label/by-uuid links (filesystem metadata)
ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-uuid/$env{ID_FS_UUID_ENC}"
ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_ENC}=="?*", SYMLINK+="disk/by-label/$env{ID_FS_LABEL_ENC}"
# by-id (World Wide Name)
ENV{DEVTYPE}=="disk", ENV{ID_WWN_WITH_EXTENSION}=="?*", SYMLINK+="disk/by-id/wwn-$env{ID_WWN_WITH_EXTENSION}"
ENV{DEVTYPE}=="partition", ENV{ID_WWN_WITH_EXTENSION}=="?*", SYMLINK+="disk/by-id/wwn-$env{ID_WWN_WITH_EXTENSION}-part%n"
# by-partlabel/by-partuuid links (partition metadata)
ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_UUID}=="?*", SYMLINK+="disk/by-partuuid/$env{ID_PART_ENTRY_UUID}"
ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_NAME}=="?*", SYMLINK+="disk/by-partlabel/$env{ID_PART_ENTRY_NAME}"
LABEL="persistent_storage_end"

View File

@ -1,2 +0,0 @@
enable dbus.socket
enable dbus-daemon.service

View File

@ -1,55 +0,0 @@
enable gdm.service
enable lightdm.service
enable slim.service
enable lxdm.service
enable sddm.service
enable kdm.service
enable xdm.service
disable systemd-timesyncd.service
disable systemd-networkd.service
disable systemd-resolved.service
# Locally-running services
enable lvm2-monitor.*
enable lvm2-lvmetad.*
enable dm-event.*
enable dmraid-activation.service
enable fstrim.timer
enable dbus.socket
enable dbus-daemon.service
enable abrtd.service
enable abrt-ccpp.service
enable abrt-oops.service
enable abrt-xorg.service
enable abrt-vmcore.service
enable xenstored.service
enable xenstored.socket
enable xenstored_ro.socket
enable xenconsoled.service
enable xen-init-dom0.service
enable libvirtd.service
enable virlockd.socket
enable upower.service
enable crond.service
# Qubes services
enable qubes-core.service
enable qubes-netvm.service
enable qubes-meminfo-writer-dom0.service
enable qubes-db-dom0.service
enable qubes-qmemman.service
enable qubes-suspend.service
enable qubes-setupdvm.service
enable qubes-qrexec-policy-daemon.service
enable qubesd.service
enable anti-evil-maid-unseal.service
enable anti-evil-maid-check-mount-devs.service
enable anti-evil-maid-seal.service

View File

@ -1 +0,0 @@
disable *

View File

@ -7,7 +7,6 @@ if modinfo cpufreq-xen > /dev/null 2>&1; then
for f in /sys/devices/system/cpu/cpu[0-9]*/cpufreq/scaling_governor; do
echo xen > $f
done
fi
if modinfo xen-acpi-processor &>/dev/null; then
modprobe xen-acpi-processor
fi

View File

@ -1 +0,0 @@
qubes-core-dom0

8
system-config/ip6tables Normal file
View File

@ -0,0 +1,8 @@
# Generated by ip6tables-save v1.4.14 on Tue Sep 25 16:00:20 2012
*filter
:INPUT DROP [1:72]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
COMMIT
# Completed on Tue Sep 25 16:00:20 2012

30
system-config/iptables Normal file
View File

@ -0,0 +1,30 @@
# Generated by iptables-save v1.4.5 on Mon Sep 6 08:57:46 2010
*nat
:PREROUTING ACCEPT [85:5912]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:PR-QBS - [0:0]
:PR-QBS-SERVICES - [0:0]
-A PREROUTING -j PR-QBS
-A PREROUTING -j PR-QBS-SERVICES
-A POSTROUTING -o vif+ -j ACCEPT
-A POSTROUTING -o lo -j ACCEPT
-A POSTROUTING -j MASQUERADE
COMMIT
# Completed on Mon Sep 6 08:57:46 2010
# Generated by iptables-save v1.4.5 on Mon Sep 6 08:57:46 2010
*filter
:INPUT ACCEPT [168:11399]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [128:12536]
-A INPUT -i vif+ -p udp -m udp --dport 68 -j DROP
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i vif+ -o vif+ -j DROP
-A FORWARD -i vif+ -j ACCEPT
-A FORWARD -j DROP
COMMIT
# Completed on Mon Sep 6 08:57:46 2010

View File

@ -2,27 +2,13 @@
COMMAND="$1"
KVER="$2"
BOOT_DIR_ABS="$3"
case "$COMMAND" in
add)
# use newer image if available
if [ -e "$BOOT_DIR_ABS"/initrd ]; then
cp -u "$BOOT_DIR_ABS"/initrd "/boot/initramfs-${KVER}.img"
fi
if [ ! -e "/boot/initramfs-${KVER}.img" ]; then
dracut "/boot/initramfs-${KVER}.img" "$KVER"
fi
dracut -f "/boot/initramfs-${KVER}.img" "$KVER"
;;
remove)
rm -f "/boot/initramfs-${KVER}.img"
;;
esac
if [ -x /usr/sbin/grub2-mkconfig ]; then
if [ -e /boot/grub2/grub.cfg ]; then
grub2-mkconfig -o /boot/grub2/grub.cfg
fi
if [ -e /boot/efi/EFI/qubes/grub.cfg ]; then
grub2-mkconfig -o /boot/efi/EFI/qubes/grub.cfg
fi
fi
grub2-mkconfig -o /boot/grub2/grub.cfg

View File

@ -1,21 +0,0 @@
#!/bin/sh
# The Boot Loader Specification is not useful for Qubes OS, because it handles
# only direct Linux boot, not Xen or any other multiboot application (like
# tboot).
# Because of that Qubes OS still uses generated grub2 configuration.
# Unfortunately the sole existence of /boot/${MACHINE_ID} changes behaviour of
# some tools - for example default output file in dracut. So forcibly remove
# the directory (which was just created...).
[[ -f /etc/machine-id ]] && read MACHINE_ID < /etc/machine-id
if [[ $MACHINE_ID ]] && ( [[ -d /boot/${MACHINE_ID} ]] || [[ -L /boot/${MACHINE_ID} ]] ); then
rm -rf /boot/${MACHINE_ID}
fi
if [[ $MACHINE_ID ]] && ( [[ -d /boot/efi/${MACHINE_ID} ]] || [[ -L /boot/efi/${MACHINE_ID} ]] ); then
rm -rf /boot/efi/${MACHINE_ID}
rm -f /boot/efi/loader/entries/${MACHINE_ID}-*.conf
# remove only when empty
rmdir /boot/efi/loader/entries /boot/efi/loader || :
fi

View File

@ -1,110 +0,0 @@
#!/bin/sh
set -e
COMMAND="$1"
KVER="$2"
ESP_MOUNTPOINT=/boot/efi
EFI_DIR=$(efibootmgr -v 2>/dev/null | awk '
/^BootCurrent:/ { current=$2; }
/^Boot....\* .*xen\.efi/ {
if ("Boot" current "*" == $1) {
sub(".*File\\(", "");
sub("\\\\xen.efi\\).*", "");
gsub("\\\\", "/");
print;
}
}')
if [ -z "$EFI_DIR" ]; then
EFI_DIR="$ESP_MOUNTPOINT/EFI/qubes"
else
EFI_DIR="$ESP_MOUNTPOINT$EFI_DIR"
fi
if [ ! -r "$EFI_DIR/xen.cfg" ]; then
# non-EFI system
exit 0;
fi
case "$COMMAND" in
add)
if ! fgrep -q "[${KVER}]" $EFI_DIR/xen.cfg; then
# take the default section and use it as a template for the new entry
awk -F = --assign "kver=${KVER}" '
/^\[/ {
# section header - previous section (if any) ended
# if default section already processed, that is all
if (in_default) exit;
in_global=0;
in_default=0;
}
/\[global\]/ {
in_global=1;
}
/^\[/ {
if ("[" default_name "]" == $0) {
in_default=1;
print "[" kver "]";
next;
}
}
/^default=/ {
if (in_global)
default_name=$2;
}
/^kernel=/ {
if (in_default) {
sub("=[^ ]*", "=vmlinuz-" kver);
}
}
/^ramdisk=/ {
if (in_default) {
sub("=[^ ]*", "=initramfs-" kver ".img");
}
}
{
if (in_default) {
print;
}
}' $EFI_DIR/xen.cfg >> $EFI_DIR/xen.cfg
# then change the default
sed -e "s/default=.*/default=$KVER/" -i $EFI_DIR/xen.cfg
fi
cp "/boot/vmlinuz-$KVER" "$EFI_DIR/"
if [ -e "/boot/initramfs-${KVER}.img" ]; then
cp -f "/boot/initramfs-${KVER}.img" "$EFI_DIR/"
else
dracut -f "$EFI_DIR/initramfs-${KVER}.img" "$KVER"
fi
;;
remove)
# don't care about changing default= line - yum should prevent removing
# currently running kernel
if [ -r $EFI_DIR/xen.cfg ]; then
awk -F = --assign "kver=${KVER}" '
/^\[/ {
# section header - previous section (if any) ended
in_current=0;
}
/^\[/ {
if ($0 == "[" kver "]")
in_current=1;
}
{
if (!in_current) {
print;
}
}' $EFI_DIR/xen.cfg > $EFI_DIR/xen.cfg.new
mv $EFI_DIR/xen.cfg.new $EFI_DIR/xen.cfg
fi
rm -f "$EFI_DIR/initramfs-${KVER}.img"
rm -f "$EFI_DIR/vmlinuz-${KVER}"
;;
esac

View File

@ -1,3 +0,0 @@
#!/bin/sh
find /etc/lvm/archive/ -type f -mtime +1 -name '*.vg' -delete

View File

@ -1 +1 @@
0 */1 * * * root /usr/bin/qvm-sync-clock > /dev/null 2>&1 || true
*/6 * * * * root /usr/bin/qvm-sync-clock > /dev/null 2>&1 || true

View File

@ -1,2 +1 @@
4.1.3
1.6.1
2.0.31

1
version_vaio_fixes Normal file
View File

@ -0,0 +1 @@
1.6.1