Merge branch 'core3-devel'
@ -4,4 +4,4 @@ language: generic
|
|||||||
install: git clone https://github.com/QubesOS/qubes-builder ~/qubes-builder
|
install: git clone https://github.com/QubesOS/qubes-builder ~/qubes-builder
|
||||||
script: ~/qubes-builder/scripts/travis-build
|
script: ~/qubes-builder/scripts/travis-build
|
||||||
env:
|
env:
|
||||||
- DIST_DOM0=fc23 USE_QUBES_REPO_VERSION=3.2 USE_QUBES_REPO_TESTING=1
|
- DIST_DOM0=fc25 USE_QUBES_REPO_VERSION=4.0 USE_QUBES_REPO_TESTING=1
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
[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
|
|
@ -1,8 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Version=1.0
|
|
||||||
Type=Application
|
|
||||||
Terminal=false
|
|
||||||
Name=Explorer
|
|
||||||
Comment=Browse files
|
|
||||||
Categories=Utility;Core;
|
|
||||||
Exec=explorer
|
|
@ -1,8 +0,0 @@
|
|||||||
[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
|
|
@ -1,10 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Version=1.0
|
|
||||||
Type=Application
|
|
||||||
Exec=qubes-vm-settings %VMNAME% applications
|
|
||||||
Icon=qubes-appmenu-select
|
|
||||||
Terminal=false
|
|
||||||
Name=%VMNAME%: Add more shortcuts...
|
|
||||||
GenericName=%VMNAME%: Add more shortcuts...
|
|
||||||
StartupNotify=false
|
|
||||||
Categories=System;X-Qubes-VM;
|
|
@ -1,10 +0,0 @@
|
|||||||
[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;X-Qubes-VM;
|
|
@ -1,10 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Version=1.0
|
|
||||||
Type=Application
|
|
||||||
Exec=sh -c 'echo xterm | /usr/lib/qubes/qfile-daemon-dvm qubes.VMShell dom0 DEFAULT red'
|
|
||||||
Icon=dispvm-red
|
|
||||||
Terminal=false
|
|
||||||
Name=DispVM: xterm
|
|
||||||
GenericName=DispVM: Terminal
|
|
||||||
StartupNotify=false
|
|
||||||
Categories=Network;X-Qubes-VM;
|
|
@ -1,5 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Encoding=UTF-8
|
|
||||||
Type=Directory
|
|
||||||
Name=DisposableVM
|
|
||||||
Icon=dispvm-red
|
|
@ -1,5 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Encoding=UTF-8
|
|
||||||
Type=Directory
|
|
||||||
Name=ServiceVM: %VMNAME%
|
|
||||||
Icon=%XDGICON%
|
|
@ -1,10 +0,0 @@
|
|||||||
[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;X-Qubes-VM;
|
|
@ -1,5 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Encoding=UTF-8
|
|
||||||
Type=Directory
|
|
||||||
Name=Template: %VMNAME%
|
|
||||||
Icon=%XDGICON%
|
|
@ -1,5 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Encoding=UTF-8
|
|
||||||
Type=Directory
|
|
||||||
Name=Domain: %VMNAME%
|
|
||||||
Icon=%XDGICON%
|
|
@ -1,20 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
SRC=$1
|
|
||||||
DSTDIR=$2
|
|
||||||
VMNAME=$3
|
|
||||||
VMDIR=$4
|
|
||||||
XDGICON=$5
|
|
||||||
|
|
||||||
DST=$DSTDIR/$VMNAME-$(basename $SRC)
|
|
||||||
|
|
||||||
if ! [ -r "$SRC" ]; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
sed \
|
|
||||||
-e "s/%VMNAME%/$VMNAME/" \
|
|
||||||
-e "s %VMDIR% $VMDIR " \
|
|
||||||
-e "s/%XDGICON%/$XDGICON/" \
|
|
||||||
<$SRC >$DST
|
|
||||||
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
|||||||
#!/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
|
|
||||||
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
|||||||
#!/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 --noupdate $APPSDIR/*.directory $APPSDIR/*.desktop
|
|
||||||
|
|
||||||
if [ -n "$KDE_SESSION_UID" -a -z "$SKIP_CACHE_REBUILD" ]; then
|
|
||||||
xdg-desktop-menu forceupdate
|
|
||||||
kbuildsycoca$KDE_SESSION_VERSION
|
|
||||||
fi
|
|
@ -1,394 +0,0 @@
|
|||||||
#!/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 vm_files, system_path
|
|
||||||
|
|
||||||
import qubes.imgconverter
|
|
||||||
|
|
||||||
vm_files['appmenus_templates_subdir'] = 'apps.templates'
|
|
||||||
vm_files['appmenus_template_icons_subdir'] = 'apps.tempicons'
|
|
||||||
vm_files['appmenus_subdir'] = 'apps'
|
|
||||||
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_appmenus_templates_dir(self):
|
|
||||||
if self.updateable:
|
|
||||||
return self.absolute_path(vm_files["appmenus_templates_subdir"], None)
|
|
||||||
elif self.template is not None:
|
|
||||||
return self.template.appmenus_templates_dir
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
QubesVm.appmenus_templates_dir = property(QubesVm_get_appmenus_templates_dir)
|
|
||||||
|
|
||||||
|
|
||||||
def QubesVm_get_appmenus_template_icons_dir(self):
|
|
||||||
if self.updateable:
|
|
||||||
return self.absolute_path(vm_files["appmenus_template_icons_subdir"],
|
|
||||||
None)
|
|
||||||
elif self.template:
|
|
||||||
return self.template.appmenus_template_icons_dir
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
QubesVm.appmenus_template_icons_dir = \
|
|
||||||
property(QubesVm_get_appmenus_template_icons_dir)
|
|
||||||
|
|
||||||
|
|
||||||
def QubesVm_get_appmenus_dir(self):
|
|
||||||
return self.absolute_path(vm_files["appmenus_subdir"], None)
|
|
||||||
|
|
||||||
QubesVm.appmenus_dir = property(QubesVm_get_appmenus_dir)
|
|
||||||
|
|
||||||
|
|
||||||
def QubesVm_get_appmenus_icons_dir(self):
|
|
||||||
return self.absolute_path(vm_files["appmenus_icons_subdir"], None)
|
|
||||||
|
|
||||||
|
|
||||||
QubesVm.appmenus_icons_dir = property(QubesVm_get_appmenus_icons_dir)
|
|
||||||
|
|
||||||
|
|
||||||
def get_whitelist_names(vm):
|
|
||||||
return (whitelist for whitelist in (
|
|
||||||
vm_files["appmenus_whitelist"],
|
|
||||||
'vm-' + vm_files["appmenus_whitelist"],
|
|
||||||
'netvm-' + vm_files["appmenus_whitelist"])
|
|
||||||
if os.path.exists(os.path.join(vm.dir_path, whitelist)))
|
|
||||||
|
|
||||||
|
|
||||||
def QubesVm_appmenus_create(self, verbose=False, source_template=None):
|
|
||||||
if source_template is None:
|
|
||||||
source_template = self.template
|
|
||||||
|
|
||||||
if self.internal:
|
|
||||||
return
|
|
||||||
if self.is_disposablevm():
|
|
||||||
return
|
|
||||||
|
|
||||||
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):
|
|
||||||
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_appmenus_cleanup(self):
|
|
||||||
srcdir = self.appmenus_templates_dir
|
|
||||||
if srcdir is None:
|
|
||||||
return
|
|
||||||
if not os.path.exists(srcdir):
|
|
||||||
return
|
|
||||||
if not os.path.exists(self.appmenus_dir):
|
|
||||||
return
|
|
||||||
|
|
||||||
for appmenu in os.listdir(self.appmenus_dir):
|
|
||||||
if not os.path.exists(os.path.join(srcdir, appmenu)):
|
|
||||||
os.unlink(os.path.join(self.appmenus_dir, appmenu))
|
|
||||||
|
|
||||||
|
|
||||||
def QubesVm_appmenus_replace_entry(self, old_name, new_name):
|
|
||||||
for whitelist in get_whitelist_names(self):
|
|
||||||
whitelist_path = os.path.join(self.dir_path, whitelist)
|
|
||||||
with open(whitelist_path) as f:
|
|
||||||
old_lines = f.readlines()
|
|
||||||
new_lines = [
|
|
||||||
(new_name + '\n' if l == old_name + '\n' else l)
|
|
||||||
for l in old_lines]
|
|
||||||
if new_lines != old_lines:
|
|
||||||
with open(whitelist_path, 'w') as f:
|
|
||||||
f.write(''.join(new_lines))
|
|
||||||
|
|
||||||
|
|
||||||
def QubesVm_appicons_create(self, srcdir=None, force=False):
|
|
||||||
if srcdir is None:
|
|
||||||
srcdir = self.appmenus_template_icons_dir
|
|
||||||
if srcdir is None:
|
|
||||||
return
|
|
||||||
if not os.path.exists(srcdir):
|
|
||||||
return
|
|
||||||
|
|
||||||
if self.internal:
|
|
||||||
return
|
|
||||||
if self.is_disposablevm():
|
|
||||||
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
|
|
||||||
|
|
||||||
src_icon = os.path.join(srcdir, icon)
|
|
||||||
dst_icon = os.path.join(self.appmenus_icons_dir, icon)
|
|
||||||
if not os.path.exists(dst_icon) or force or \
|
|
||||||
os.path.getmtime(src_icon) > os.path.getmtime(dst_icon):
|
|
||||||
qubes.imgconverter.tint(src_icon, dst_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_appicons_cleanup(self):
|
|
||||||
srcdir = self.appmenus_template_icons_dir
|
|
||||||
if srcdir is None:
|
|
||||||
return
|
|
||||||
if not os.path.exists(srcdir):
|
|
||||||
return
|
|
||||||
if not os.path.exists(self.appmenus_icons_dir):
|
|
||||||
return
|
|
||||||
|
|
||||||
for icon in os.listdir(self.appmenus_icons_dir):
|
|
||||||
if not os.path.exists(os.path.join(srcdir, icon)):
|
|
||||||
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):
|
|
||||||
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 get_whitelist_names(src_vm):
|
|
||||||
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(force=True)
|
|
||||||
|
|
||||||
# Apparently desktop environments heavily caches the icons,
|
|
||||||
# see #751 for details
|
|
||||||
if "plasma" in os.environ.get("DESKTOP_SESSION", ""):
|
|
||||||
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 "xfce" in os.environ.get("DESKTOP_SESSION", ""):
|
|
||||||
self.appmenus_remove()
|
|
||||||
self.appmenus_create()
|
|
||||||
|
|
||||||
|
|
||||||
def QubesVm_appmenus_recreate(self):
|
|
||||||
"""
|
|
||||||
Force recreation of all appmenus and icons. For example when VM label
|
|
||||||
color was changed
|
|
||||||
"""
|
|
||||||
self.appmenus_remove()
|
|
||||||
self.appmenus_cleanup()
|
|
||||||
self.appicons_remove()
|
|
||||||
self.appicons_create()
|
|
||||||
self.appmenus_create()
|
|
||||||
|
|
||||||
|
|
||||||
def QubesVm_appmenus_update(self):
|
|
||||||
"""
|
|
||||||
Similar to appmenus_recreate, but do not touch unchanged files
|
|
||||||
"""
|
|
||||||
self.appmenus_remove()
|
|
||||||
self.appmenus_cleanup()
|
|
||||||
self.appicons_create()
|
|
||||||
self.appicons_cleanup()
|
|
||||||
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_cleanup = QubesVm_appmenus_cleanup
|
|
||||||
QubesVm.appmenus_recreate = QubesVm_appmenus_recreate
|
|
||||||
QubesVm.appmenus_update = QubesVm_appmenus_update
|
|
||||||
QubesVm.appmenus_replace_entry = QubesVm_appmenus_replace_entry
|
|
||||||
QubesVm.appicons_create = QubesVm_appicons_create
|
|
||||||
QubesVm.appicons_cleanup = QubesVm_appicons_cleanup
|
|
||||||
QubesVm.appicons_remove = QubesVm_appicons_remove
|
|
||||||
|
|
||||||
# hooks for existing methods
|
|
||||||
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)
|
|
@ -1,392 +0,0 @@
|
|||||||
#!/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 optparse
|
|
||||||
|
|
||||||
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
|
|
||||||
from qubes.qubes import vmm
|
|
||||||
|
|
||||||
# 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 = {
|
|
||||||
# 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,
|
|
||||||
gui=False)
|
|
||||||
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")
|
|
||||||
|
|
||||||
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 untrusted_key in fields_regexp:
|
|
||||||
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 filename not in appmenus:
|
|
||||||
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 key not in values:
|
|
||||||
print >> sys.stderr, "Warning: not creating/updating '%s' " \
|
|
||||||
"because of missing '%s' key" % (
|
|
||||||
path, key)
|
|
||||||
return
|
|
||||||
|
|
||||||
desktop_entry = ""
|
|
||||||
desktop_entry += "[Desktop Entry]\n"
|
|
||||||
desktop_entry += "Version=1.0\n"
|
|
||||||
desktop_entry += "Type=Application\n"
|
|
||||||
desktop_entry += "Terminal=false\n"
|
|
||||||
desktop_entry += "X-Qubes-VmName=%VMNAME%\n"
|
|
||||||
|
|
||||||
if 'Icon' in values:
|
|
||||||
icon_file = os.path.splitext(os.path.split(path)[1])[0] + '.png'
|
|
||||||
desktop_entry += "Icon={0}\n".format(os.path.join(
|
|
||||||
'%VMDIR%', vm_files['appmenus_icons_subdir'], icon_file))
|
|
||||||
else:
|
|
||||||
desktop_entry += "Icon=%XDGICON%\n"
|
|
||||||
|
|
||||||
for key in ["Name", "GenericName"]:
|
|
||||||
if key in values:
|
|
||||||
desktop_entry += "{0}=%VMNAME%: {1}\n".format(key, values[key])
|
|
||||||
|
|
||||||
# force category X-Qubes-VM
|
|
||||||
values["Categories"] = values.get("Categories", "") + "X-Qubes-VM;"
|
|
||||||
|
|
||||||
for key in ["Comment", "Categories"]:
|
|
||||||
if key in values:
|
|
||||||
desktop_entry += "{0}={1}\n".format(key, values[key])
|
|
||||||
|
|
||||||
desktop_entry += "Exec=qvm-run -q --tray -a %VMNAME% -- {0}\n".format(
|
|
||||||
pipes.quote(values['Exec']))
|
|
||||||
if not os.path.exists(path) or desktop_entry != open(path, "r").read():
|
|
||||||
desktop_file = open(path, "w")
|
|
||||||
desktop_file.write(desktop_entry)
|
|
||||||
desktop_file.close()
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
env_vmname = os.environ.get("QREXEC_REMOTE_DOMAIN")
|
|
||||||
usage = "usage: %prog [options] <vm-name>\n" \
|
|
||||||
"Update 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")
|
|
||||||
# Do not use any RPC call, expects data on stdin (in qubes.GetAppmenus
|
|
||||||
# format)
|
|
||||||
parser.add_option("--offline-mode", dest="offline_mode",
|
|
||||||
action="store_true", default=False,
|
|
||||||
help=optparse.SUPPRESS_HELP)
|
|
||||||
|
|
||||||
(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 into " \
|
|
||||||
"permissions problems."
|
|
||||||
print >> sys.stderr, "Retry as unprivileged user."
|
|
||||||
print >> sys.stderr, "... or use --force-root to continue anyway."
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
if options.offline_mode:
|
|
||||||
vmm.offline_mode = True
|
|
||||||
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 options.offline_mode and not vm.is_running():
|
|
||||||
print >> sys.stderr, "ERROR: Appmenus can be retrieved only from " \
|
|
||||||
"running VM - start it first"
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
if not options.offline_mode and 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)
|
|
||||||
|
|
||||||
os.umask(002)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
# TODO: icons support in offline mode
|
|
||||||
if options.offline_mode:
|
|
||||||
new_appmenus[appmenu_file].pop('Icon', None)
|
|
||||||
if 'Icon' in new_appmenus[appmenu_file]:
|
|
||||||
# the following line is used for time comparison
|
|
||||||
icondest = os.path.join(vm.appmenus_template_icons_dir,
|
|
||||||
os.path.splitext(appmenu_file)[0] + '.png')
|
|
||||||
|
|
||||||
try:
|
|
||||||
icon = qubes.imgconverter.Image. \
|
|
||||||
get_xdg_icon_from_vm(vm,
|
|
||||||
new_appmenus[
|
|
||||||
appmenu_file][
|
|
||||||
'Icon'])
|
|
||||||
if os.path.exists(icondest):
|
|
||||||
old_icon = qubes.imgconverter.Image.load_from_file(icondest)
|
|
||||||
else:
|
|
||||||
old_icon = None
|
|
||||||
if old_icon is None or icon != old_icon:
|
|
||||||
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 appmenu_file not in new_appmenus:
|
|
||||||
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)
|
|
||||||
|
|
||||||
vm.appmenus_update()
|
|
||||||
if hasattr(vm, 'appvms'):
|
|
||||||
os.putenv('SKIP_CACHE_REBUILD', '1')
|
|
||||||
for child_vm in vm.appvms.values():
|
|
||||||
try:
|
|
||||||
child_vm.appmenus_update()
|
|
||||||
except Exception, e:
|
|
||||||
print >> sys.stderr, "---> Failed to recreate appmenus for " \
|
|
||||||
"'{0}': {1}".format(child_vm.name, str(e))
|
|
||||||
subprocess.call(['xdg-desktop-menu', 'forceupdate'])
|
|
||||||
if 'KDE_SESSION_UID' in os.environ:
|
|
||||||
subprocess.call(['kbuildsycoca' + os.environ.get('KDE_SESSION_VERSION', '4')])
|
|
||||||
os.unsetenv('SKIP_CACHE_REBUILD')
|
|
||||||
|
|
||||||
|
|
||||||
main()
|
|
@ -1 +0,0 @@
|
|||||||
/usr/libexec/qubes-appmenus/qubes-receive-appmenus
|
|
@ -1,56 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# The Qubes OS Project, http://www.qubes-os.org
|
|
||||||
#
|
|
||||||
# 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 sys
|
|
||||||
from qubes.qubes import QubesVmCollection
|
|
||||||
|
|
||||||
def main():
|
|
||||||
if len(sys.argv) != 4:
|
|
||||||
print >> sys.stderr, \
|
|
||||||
'Usage: qvm-appmenu-replace VM_NAME OLD_NAME.desktop NEW_NAME.desktop'
|
|
||||||
sys.exit(1)
|
|
||||||
vm_name = sys.argv[1]
|
|
||||||
old_name = sys.argv[2]
|
|
||||||
new_name = sys.argv[3]
|
|
||||||
|
|
||||||
qvm_collection = QubesVmCollection()
|
|
||||||
qvm_collection.lock_db_for_reading()
|
|
||||||
qvm_collection.load()
|
|
||||||
qvm_collection.unlock_db()
|
|
||||||
|
|
||||||
vm = qvm_collection.get_vm_by_name(vm_name)
|
|
||||||
|
|
||||||
if vm is None:
|
|
||||||
print >> sys.stderr, "ERROR: A VM with the name '{0}' " \
|
|
||||||
"does not exist in the system.".format(
|
|
||||||
vm_name)
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
if vm.template is not None:
|
|
||||||
print >> sys.stderr, "ERROR: To replace appmenu for template based VM, " \
|
|
||||||
"do it on template instead"
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
vm.appmenus_replace_entry(old_name, new_name)
|
|
||||||
if hasattr(vm, 'appvms'):
|
|
||||||
for child_vm in vm.appvms.values():
|
|
||||||
child_vm.appmenus_replace_entry(old_name, new_name)
|
|
||||||
|
|
||||||
main()
|
|
@ -1,2 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
exec /usr/libexec/qubes-appmenus/qubes-receive-appmenus $@
|
|
@ -1,23 +0,0 @@
|
|||||||
#!/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" -a -z "$SKIP_CACHE_REBUILD" ]; then
|
|
||||||
kbuildsycoca$KDE_SESSION_VERSION
|
|
||||||
fi
|
|
@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
UPDATEVM=`qubes-prefs --get updatevm`
|
UPDATEVM=`qubes-prefs --force-root updatevm`
|
||||||
UPDATES_STAT_FILE=/var/lib/qubes/updates/dom0-updates-available
|
UPDATES_STAT_FILE=/var/lib/qubes/updates/dom0-updates-available
|
||||||
|
|
||||||
if [ -z "$UPDATEVM" ]; then
|
if [ -z "$UPDATEVM" ]; then
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/python2
|
#!/usr/bin/python3
|
||||||
#
|
#
|
||||||
# The Qubes OS Project, http://www.qubes-os.org
|
# The Qubes OS Project, http://www.qubes-os.org
|
||||||
#
|
#
|
||||||
@ -18,16 +18,14 @@
|
|||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#
|
#
|
||||||
#
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import subprocess
|
import subprocess
|
||||||
import shutil
|
import shutil
|
||||||
import glob
|
|
||||||
import grp
|
import grp
|
||||||
from qubes.qubes import QubesVmCollection
|
import qubes
|
||||||
|
|
||||||
updates_dir = "/var/lib/qubes/updates"
|
updates_dir = "/var/lib/qubes/updates"
|
||||||
updates_rpm_dir = updates_dir + "/rpm"
|
updates_rpm_dir = updates_dir + "/rpm"
|
||||||
@ -48,20 +46,23 @@ package_regex = re.compile(r"^[A-Za-z0-9._+-]{1,128}.rpm$")
|
|||||||
# .....rpm: RSA sha1 ((MD5) PGP) md5 NOT OK (MISSING KEYS: (MD5) PGP#246110c1)
|
# .....rpm: RSA sha1 ((MD5) PGP) md5 NOT OK (MISSING KEYS: (MD5) PGP#246110c1)
|
||||||
gpg_ok_regex = re.compile(r": [a-z0-9() ]* (pgp|gpg) [a-z0-9 ]*OK$")
|
gpg_ok_regex = re.compile(r": [a-z0-9() ]* (pgp|gpg) [a-z0-9 ]*OK$")
|
||||||
|
|
||||||
|
|
||||||
def dom0updates_fatal(pkg, msg):
|
def dom0updates_fatal(pkg, msg):
|
||||||
global updates_error_file_handle
|
global updates_error_file_handle
|
||||||
print >> sys.stderr, msg
|
print(msg, file=sys.stderr)
|
||||||
if updates_error_file_handle is None:
|
if updates_error_file_handle is None:
|
||||||
updates_error_file_handle = open(updates_error_file, "a")
|
updates_error_file_handle = open(updates_error_file, "a")
|
||||||
updates_error_file_handle.write(msg + "\n")
|
updates_error_file_handle.write(msg + "\n")
|
||||||
os.remove(pkg)
|
os.remove(pkg)
|
||||||
|
|
||||||
|
|
||||||
def handle_dom0updates(updatevm):
|
def handle_dom0updates(updatevm):
|
||||||
global updates_error_file_handle
|
global updates_error_file_handle
|
||||||
|
|
||||||
source=os.getenv("QREXEC_REMOTE_DOMAIN")
|
source = os.getenv("QREXEC_REMOTE_DOMAIN")
|
||||||
if source != updatevm.name:
|
if source != updatevm.name:
|
||||||
print >> sys.stderr, 'Domain ' + str(source) + ' not allowed to send dom0 updates'
|
print('Domain ' + str(source) + ' not allowed to send dom0 updates',
|
||||||
|
file=sys.stderr)
|
||||||
exit(1)
|
exit(1)
|
||||||
# Clean old packages
|
# Clean old packages
|
||||||
if os.path.exists(updates_rpm_dir):
|
if os.path.exists(updates_rpm_dir):
|
||||||
@ -72,15 +73,17 @@ def handle_dom0updates(updatevm):
|
|||||||
os.remove(updates_error_file)
|
os.remove(updates_error_file)
|
||||||
os.environ['LC_ALL'] = 'C'
|
os.environ['LC_ALL'] = 'C'
|
||||||
qubes_gid = grp.getgrnam('qubes').gr_gid
|
qubes_gid = grp.getgrnam('qubes').gr_gid
|
||||||
old_umask = os.umask(002)
|
old_umask = os.umask(0o002)
|
||||||
os.mkdir(updates_rpm_dir)
|
os.mkdir(updates_rpm_dir)
|
||||||
os.chown(updates_rpm_dir, -1, qubes_gid)
|
os.chown(updates_rpm_dir, -1, qubes_gid)
|
||||||
os.chmod(updates_rpm_dir, 0775)
|
os.chmod(updates_rpm_dir, 0o0775)
|
||||||
subprocess.check_call(["/usr/libexec/qubes/qfile-dom0-unpacker", str(os.getuid()), updates_rpm_dir])
|
subprocess.check_call(["/usr/libexec/qubes/qfile-dom0-unpacker",
|
||||||
|
str(os.getuid()), updates_rpm_dir])
|
||||||
# Verify received files
|
# Verify received files
|
||||||
for untrusted_f in os.listdir(updates_rpm_dir):
|
for untrusted_f in os.listdir(updates_rpm_dir):
|
||||||
if not package_regex.match(untrusted_f):
|
if not package_regex.match(untrusted_f):
|
||||||
dom0updates_fatal(updates_rpm_dir + '/' + untrusted_f, 'Domain ' + source + ' sent unexpected file: ' + untrusted_f)
|
dom0updates_fatal(updates_rpm_dir + '/' + untrusted_f,
|
||||||
|
'Domain ' + source + ' sent unexpected file: ' + untrusted_f)
|
||||||
else:
|
else:
|
||||||
f = untrusted_f
|
f = untrusted_f
|
||||||
assert '/' not in f
|
assert '/' not in f
|
||||||
@ -89,14 +92,17 @@ def handle_dom0updates(updatevm):
|
|||||||
|
|
||||||
full_path = updates_rpm_dir + "/" + f
|
full_path = updates_rpm_dir + "/" + f
|
||||||
if os.path.islink(full_path) or not os.path.isfile(full_path):
|
if os.path.islink(full_path) or not os.path.isfile(full_path):
|
||||||
dom0updates_fatal(full_path, 'Domain ' + source + ' sent not regular file')
|
dom0updates_fatal(
|
||||||
p = subprocess.Popen (["/bin/rpm", "-K", full_path],
|
full_path, 'Domain ' + source + ' sent not regular file')
|
||||||
|
p = subprocess.Popen(["/bin/rpm", "-K", full_path],
|
||||||
stdout=subprocess.PIPE)
|
stdout=subprocess.PIPE)
|
||||||
output = p.communicate()[0]
|
output = p.communicate()[0].decode('ascii')
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
dom0updates_fatal(full_path, '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()):
|
if not gpg_ok_regex.search(output.strip()):
|
||||||
dom0updates_fatal(full_path, 'Domain ' + source + ' sent not signed rpm: ' + f)
|
dom0updates_fatal(full_path,
|
||||||
|
'Domain ' + source + ' sent not signed rpm: ' + f)
|
||||||
if updates_error_file_handle is not None:
|
if updates_error_file_handle is not None:
|
||||||
updates_error_file_handle.close()
|
updates_error_file_handle.close()
|
||||||
# After updates received - create repo metadata
|
# After updates received - create repo metadata
|
||||||
@ -106,27 +112,28 @@ def handle_dom0updates(updatevm):
|
|||||||
createrepo_cmd += ["-q", updates_dir]
|
createrepo_cmd += ["-q", updates_dir]
|
||||||
subprocess.check_call(createrepo_cmd)
|
subprocess.check_call(createrepo_cmd)
|
||||||
os.chown(updates_repodata_dir, -1, qubes_gid)
|
os.chown(updates_repodata_dir, -1, qubes_gid)
|
||||||
os.chmod(updates_repodata_dir, 0775)
|
os.chmod(updates_repodata_dir, 0o0775)
|
||||||
# Clean old cache
|
# Clean old cache
|
||||||
subprocess.call(["sudo", "/usr/bin/yum", "-q", "clean", "all"], stdout=sys.stderr)
|
subprocess.call(["sudo", "/usr/bin/yum", "-q", "clean", "all"],
|
||||||
# This will fail because of "smart" detection of no-network, but it will invalidate the cache
|
stdout=sys.stderr)
|
||||||
|
# This will fail because of "smart" detection of no-network,
|
||||||
|
# but it will invalidate the cache
|
||||||
try:
|
try:
|
||||||
null = open('/dev/null','w')
|
null = open('/dev/null', 'w')
|
||||||
subprocess.call(["/usr/bin/pkcon", "refresh"], stdout=null)
|
subprocess.call(["/usr/bin/pkcon", "refresh"], stdout=null)
|
||||||
null.close()
|
null.close()
|
||||||
except:
|
except subprocess.CalledProcessError:
|
||||||
pass
|
pass
|
||||||
os.umask(old_umask)
|
os.umask(old_umask)
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
app = qubes.Qubes()
|
||||||
|
|
||||||
qvm_collection = QubesVmCollection()
|
updatevm = app.updatevm
|
||||||
qvm_collection.lock_db_for_reading()
|
if updatevm is None:
|
||||||
qvm_collection.load()
|
exit(1)
|
||||||
qvm_collection.unlock_db()
|
|
||||||
|
|
||||||
updatevm = qvm_collection.get_updatevm_vm()
|
|
||||||
handle_dom0updates(updatevm)
|
handle_dom0updates(updatevm)
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
BIN
icons/black.png
Before Width: | Height: | Size: 169 KiB |
BIN
icons/blue.png
Before Width: | Height: | Size: 181 KiB |
@ -1,10 +0,0 @@
|
|||||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
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.
|
|
@ -1 +0,0 @@
|
|||||||
dom0-update-avail icon from gnome-packagekit project distributed under GPLv2
|
|
@ -1 +0,0 @@
|
|||||||
Color padlock images downloaded from www.openclipart.org
|
|
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 2.5 KiB |
BIN
icons/gray.png
Before Width: | Height: | Size: 192 KiB |
BIN
icons/green.png
Before Width: | Height: | Size: 187 KiB |
BIN
icons/netvm.png
Before Width: | Height: | Size: 15 KiB |
BIN
icons/orange.png
Before Width: | Height: | Size: 188 KiB |
BIN
icons/purple.png
Before Width: | Height: | Size: 188 KiB |
BIN
icons/qubes.png
Before Width: | Height: | Size: 20 KiB |
BIN
icons/red.png
Before Width: | Height: | Size: 177 KiB |
Before Width: | Height: | Size: 20 KiB |
BIN
icons/yellow.png
Before Width: | Height: | Size: 185 KiB |
@ -545,12 +545,13 @@ static void select_loop(libvchan_t *vchan)
|
|||||||
static void usage(char *name)
|
static void usage(char *name)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"usage: %s [-w timeout] [-t] [-T] -d domain_name ["
|
"usage: %s [-w timeout] [-W] [-t] [-T] -d domain_name ["
|
||||||
"-l local_prog|"
|
"-l local_prog|"
|
||||||
"-c request_id,src_domain_name,src_domain_id|"
|
"-c request_id,src_domain_name,src_domain_id|"
|
||||||
"-e] remote_cmdline\n"
|
"-e] remote_cmdline\n"
|
||||||
"-e means exit after sending cmd,\n"
|
"-e means exit after sending cmd,\n"
|
||||||
"-t enables replacing problematic bytes with '_' in command output, -T is the same for stderr\n"
|
"-t enables replacing problematic bytes with '_' in command output, -T is the same for stderr\n"
|
||||||
|
"-W waits for connection end even in case of VM-VM (-c)\n"
|
||||||
"-c: connect to existing process (response to trigger service call)\n"
|
"-c: connect to existing process (response to trigger service call)\n"
|
||||||
"-w timeout: override default connection timeout of 5s (set 0 for no timeout)\n",
|
"-w timeout: override default connection timeout of 5s (set 0 for no timeout)\n",
|
||||||
name);
|
name);
|
||||||
@ -649,6 +650,7 @@ int main(int argc, char **argv)
|
|||||||
int msg_type;
|
int msg_type;
|
||||||
int s;
|
int s;
|
||||||
int just_exec = 0;
|
int just_exec = 0;
|
||||||
|
int wait_connection_end = 0;
|
||||||
int connect_existing = 0;
|
int connect_existing = 0;
|
||||||
char *local_cmdline = NULL;
|
char *local_cmdline = NULL;
|
||||||
char *remote_cmdline = NULL;
|
char *remote_cmdline = NULL;
|
||||||
@ -657,7 +659,7 @@ int main(int argc, char **argv)
|
|||||||
int src_domain_id = 0; /* if not -c given, the process is run in dom0 */
|
int src_domain_id = 0; /* if not -c given, the process is run in dom0 */
|
||||||
int connection_timeout = 5;
|
int connection_timeout = 5;
|
||||||
struct service_params svc_params;
|
struct service_params svc_params;
|
||||||
while ((opt = getopt(argc, argv, "d:l:ec:tTw:")) != -1) {
|
while ((opt = getopt(argc, argv, "d:l:ec:tTw:W")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'd':
|
case 'd':
|
||||||
domname = strdup(optarg);
|
domname = strdup(optarg);
|
||||||
@ -682,6 +684,9 @@ int main(int argc, char **argv)
|
|||||||
case 'w':
|
case 'w':
|
||||||
connection_timeout = atoi(optarg);
|
connection_timeout = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'W':
|
||||||
|
wait_connection_end = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
}
|
}
|
||||||
@ -757,13 +762,25 @@ int main(int argc, char **argv)
|
|||||||
strlen(remote_cmdline) + 1,
|
strlen(remote_cmdline) + 1,
|
||||||
&data_domain,
|
&data_domain,
|
||||||
&data_port);
|
&data_port);
|
||||||
close(s);
|
if (wait_connection_end && connect_existing)
|
||||||
|
/* save socket fd, 's' will be reused for the other qrexec-daemon
|
||||||
|
* connection */
|
||||||
|
wait_connection_end = s;
|
||||||
|
else
|
||||||
|
close(s);
|
||||||
setenv("QREXEC_REMOTE_DOMAIN", domname, 1);
|
setenv("QREXEC_REMOTE_DOMAIN", domname, 1);
|
||||||
prepare_local_fds(local_cmdline);
|
prepare_local_fds(local_cmdline);
|
||||||
if (connect_existing) {
|
if (connect_existing) {
|
||||||
s = connect_unix_socket(src_domain_name);
|
s = connect_unix_socket(src_domain_name);
|
||||||
send_service_connect(s, request_id, data_domain, data_port);
|
send_service_connect(s, request_id, data_domain, data_port);
|
||||||
close(s);
|
close(s);
|
||||||
|
if (wait_connection_end) {
|
||||||
|
/* wait for EOF */
|
||||||
|
fd_set read_fd;
|
||||||
|
FD_ZERO(&read_fd);
|
||||||
|
FD_SET(wait_connection_end, &read_fd);
|
||||||
|
select(wait_connection_end+1, &read_fd, NULL, NULL, 0);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
data_vchan = libvchan_server_init(data_domain, data_port,
|
data_vchan = libvchan_server_init(data_domain, data_port,
|
||||||
VCHAN_BUFFER_SIZE, VCHAN_BUFFER_SIZE);
|
VCHAN_BUFFER_SIZE, VCHAN_BUFFER_SIZE);
|
||||||
|
@ -71,6 +71,12 @@ int policy_pending_max = -1;
|
|||||||
* either VCHAN_PORT_* or remote domain id for used port */
|
* either VCHAN_PORT_* or remote domain id for used port */
|
||||||
int used_vchan_ports[MAX_CLIENTS];
|
int used_vchan_ports[MAX_CLIENTS];
|
||||||
|
|
||||||
|
/* notify client (close its connection) when connection initiated by it was
|
||||||
|
* terminated - used by qrexec-policy to cleanup (disposable) VM; indexed with
|
||||||
|
* vchan port number relative to VCHAN_BASE_DATA_PORT; stores fd of given
|
||||||
|
* client or -1 if none requested */
|
||||||
|
int vchan_port_notify_client[MAX_CLIENTS];
|
||||||
|
|
||||||
int max_client_fd = -1; // current max fd of all clients; so that we need not to scan all the "clients" table
|
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
|
int qrexec_daemon_unix_socket_fd; // /var/run/qubes/qrexec.xid descriptor
|
||||||
const char *default_user = "user";
|
const char *default_user = "user";
|
||||||
@ -312,6 +318,7 @@ void init(int xid)
|
|||||||
clients[i].state = CLIENT_INVALID;
|
clients[i].state = CLIENT_INVALID;
|
||||||
policy_pending[i].pid = 0;
|
policy_pending[i].pid = 0;
|
||||||
used_vchan_ports[i] = VCHAN_PORT_UNUSED;
|
used_vchan_ports[i] = VCHAN_PORT_UNUSED;
|
||||||
|
vchan_port_notify_client[i] = VCHAN_PORT_UNUSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* When running as root, make the socket accessible; perms on /var/run/qubes still apply */
|
/* When running as root, make the socket accessible; perms on /var/run/qubes still apply */
|
||||||
@ -358,14 +365,6 @@ static int allocate_vchan_port(int new_state)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void release_vchan_port(int port, int expected_remote_id)
|
|
||||||
{
|
|
||||||
/* release only if was reserved for connection to given domain */
|
|
||||||
if (used_vchan_ports[port-VCHAN_BASE_DATA_PORT] == expected_remote_id) {
|
|
||||||
used_vchan_ports[port-VCHAN_BASE_DATA_PORT] = VCHAN_PORT_UNUSED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_new_client()
|
static void handle_new_client()
|
||||||
{
|
{
|
||||||
int fd = do_accept(qrexec_daemon_unix_socket_fd);
|
int fd = do_accept(qrexec_daemon_unix_socket_fd);
|
||||||
@ -387,8 +386,25 @@ static void handle_new_client()
|
|||||||
|
|
||||||
static void terminate_client(int fd)
|
static void terminate_client(int fd)
|
||||||
{
|
{
|
||||||
|
int port;
|
||||||
clients[fd].state = CLIENT_INVALID;
|
clients[fd].state = CLIENT_INVALID;
|
||||||
close(fd);
|
close(fd);
|
||||||
|
/* if client requested vchan connection end notify, cancel it */
|
||||||
|
for (port = 0; port < MAX_CLIENTS; port++) {
|
||||||
|
if (vchan_port_notify_client[port] == fd)
|
||||||
|
vchan_port_notify_client[port] = VCHAN_PORT_UNUSED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void release_vchan_port(int port, int expected_remote_id)
|
||||||
|
{
|
||||||
|
/* release only if was reserved for connection to given domain */
|
||||||
|
if (used_vchan_ports[port-VCHAN_BASE_DATA_PORT] == expected_remote_id) {
|
||||||
|
used_vchan_ports[port-VCHAN_BASE_DATA_PORT] = VCHAN_PORT_UNUSED;
|
||||||
|
/* notify client if requested - it will clear notification request */
|
||||||
|
if (vchan_port_notify_client[port-VCHAN_BASE_DATA_PORT] != VCHAN_PORT_UNUSED)
|
||||||
|
terminate_client(vchan_port_notify_client[port-VCHAN_BASE_DATA_PORT]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_cmdline_body_from_client(int fd, struct msg_header *hdr)
|
static int handle_cmdline_body_from_client(int fd, struct msg_header *hdr)
|
||||||
@ -433,6 +449,8 @@ static int handle_cmdline_body_from_client(int fd, struct msg_header *hdr)
|
|||||||
terminate_client(fd);
|
terminate_client(fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/* notify the client when this connection got terminated */
|
||||||
|
vchan_port_notify_client[params.connect_port-VCHAN_BASE_DATA_PORT] = fd;
|
||||||
client_params.connect_port = params.connect_port;
|
client_params.connect_port = params.connect_port;
|
||||||
client_params.connect_domain = remote_domain_id;
|
client_params.connect_domain = remote_domain_id;
|
||||||
hdr->len = sizeof(client_params);
|
hdr->len = sizeof(client_params);
|
||||||
@ -694,7 +712,7 @@ static void handle_execute_service(void)
|
|||||||
signal(SIGPIPE, SIG_DFL);
|
signal(SIGPIPE, SIG_DFL);
|
||||||
snprintf(remote_domain_id_str, sizeof(remote_domain_id_str), "%d",
|
snprintf(remote_domain_id_str, sizeof(remote_domain_id_str), "%d",
|
||||||
remote_domain_id);
|
remote_domain_id);
|
||||||
execl("/usr/lib/qubes/qrexec-policy", "qrexec-policy", "--",
|
execl("/usr/bin/qrexec-policy", "qrexec-policy", "--",
|
||||||
remote_domain_id_str, remote_domain_name, params.target_domain,
|
remote_domain_id_str, remote_domain_name, params.target_domain,
|
||||||
params.service_name, params.request_id.ident, NULL);
|
params.service_name, params.request_id.ident, NULL);
|
||||||
perror("execl");
|
perror("execl");
|
||||||
|
@ -1,257 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import os.path
|
|
||||||
import subprocess
|
|
||||||
from qubes.qubes import vmm
|
|
||||||
from qubes.qubes import QubesVmCollection
|
|
||||||
import qubes.guihelpers
|
|
||||||
import libvirt
|
|
||||||
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"
|
|
||||||
QUBES_RPC_MULTIPLEXER_PATH="/usr/lib/qubes/qubes-rpc-multiplexer"
|
|
||||||
|
|
||||||
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(service_name):
|
|
||||||
policy_file = os.path.join(POLICY_FILE_DIR, service_name)
|
|
||||||
if not os.path.isfile(policy_file):
|
|
||||||
# fallback to policy without specific argument set (if any)
|
|
||||||
policy_file = os.path.join(POLICY_FILE_DIR, service_name.split("+")[0])
|
|
||||||
if not os.path.isfile(policy_file):
|
|
||||||
policy_file = os.path.join(DEPRECATED_POLICY_FILE_DIR, service_name)
|
|
||||||
if not os.path.isfile(policy_file):
|
|
||||||
return None
|
|
||||||
print >>sys.stderr, "RPC service '%s' uses deprecated policy location, please move to %s" % (service_name, 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 != "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 validate_target(target):
|
|
||||||
# special targets
|
|
||||||
if target in ['$dispvm']:
|
|
||||||
return True
|
|
||||||
|
|
||||||
qc = QubesVmCollection()
|
|
||||||
qc.lock_db_for_reading()
|
|
||||||
qc.load()
|
|
||||||
qc.unlock_db()
|
|
||||||
|
|
||||||
return qc.get_vm_by_name(target)
|
|
||||||
|
|
||||||
def spawn_target_if_necessary(vm):
|
|
||||||
if vm.is_running():
|
|
||||||
return
|
|
||||||
# use qvm-run instead of vm.start() to make sure that nothing is written
|
|
||||||
# to stdout and nothing is read from stdin
|
|
||||||
null = open("/dev/null", "r+")
|
|
||||||
subprocess.call(["qvm-run", "-a", "--tray", "-q", vm.name, "true"],
|
|
||||||
stdin=null, stdout=null)
|
|
||||||
null.close()
|
|
||||||
|
|
||||||
def do_execute(domain, target, user, service_name, process_ident, vm=None):
|
|
||||||
if target == "$dispvm":
|
|
||||||
cmd = "/usr/lib/qubes/qfile-daemon-dvm " + service_name + " " + domain + " " +user
|
|
||||||
os.execl(QREXEC_CLIENT, "qrexec-client",
|
|
||||||
"-d", "dom0", "-c", process_ident, cmd)
|
|
||||||
else:
|
|
||||||
if isinstance(vm, qubes.qubes.QubesVm):
|
|
||||||
spawn_target_if_necessary(vm)
|
|
||||||
if target == "dom0":
|
|
||||||
cmd = QUBES_RPC_MULTIPLEXER_PATH + " " + service_name + " " + domain
|
|
||||||
else:
|
|
||||||
cmd = user + ":QUBESRPC "+ service_name + " " + 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", target, "-c", process_ident, cmd)
|
|
||||||
|
|
||||||
def confirm_execution(domain, target, service_name):
|
|
||||||
text = "Do you allow domain \"" +domain + "\" to execute " + service_name
|
|
||||||
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, service_name, options):
|
|
||||||
policy_file=POLICY_FILE_DIR+"/"+service_name
|
|
||||||
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 info_dialog(msg_type, text):
|
|
||||||
if msg_type not in ['info', 'warning', 'error', 'entry']:
|
|
||||||
raise ValueError("Invalid msg_type value")
|
|
||||||
if msg_type in ['info', 'warning', 'error']:
|
|
||||||
try:
|
|
||||||
subprocess.call(["/usr/bin/zenity", "--{}".format(msg_type), "--text",
|
|
||||||
text])
|
|
||||||
except OSError:
|
|
||||||
kdialog_msg_type = {
|
|
||||||
'info': 'msgbox',
|
|
||||||
'warning': 'sorry',
|
|
||||||
'error': 'error'
|
|
||||||
}[msg_type]
|
|
||||||
subprocess.call(["/usr/bin/kdialog", "--{}".format(kdialog_msg_type), text])
|
|
||||||
else:
|
|
||||||
response = subprocess.check_output(["/usr/bin/zenity", "--{}".format(msg_type), "--text",
|
|
||||||
text])
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
def policy_editor(domain, target, service_name):
|
|
||||||
text = "No policy definition found for " + service_name + " action. \n"
|
|
||||||
text+= "Type YES if you want to create a default policy file"
|
|
||||||
response = info_dialog('entry', text)
|
|
||||||
if response.strip() == 'YES':
|
|
||||||
create_policy(service_name)
|
|
||||||
|
|
||||||
|
|
||||||
def create_policy(service_name):
|
|
||||||
policyFile = "/etc/qubes-rpc/policy/"+service_name
|
|
||||||
policy = open(policyFile, "w")
|
|
||||||
policy.write("## Note that policy parsing stops at the first match,\n")
|
|
||||||
policy.write("## so adding anything below \"$anyvm $anyvm action\" line will have no effect\n")
|
|
||||||
policy.write("\n")
|
|
||||||
policy.write("## Please use a single # to start your custom comments\n")
|
|
||||||
policy.write("\n")
|
|
||||||
policy.write("$anyvm $anyvm ask\n")
|
|
||||||
policy.close()
|
|
||||||
|
|
||||||
def main():
|
|
||||||
usage = "usage: %prog [options] <src-domain-id> <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_id=args[0]
|
|
||||||
domain=args[1]
|
|
||||||
target=args[2]
|
|
||||||
service_name=args[3]
|
|
||||||
process_ident=args[4]
|
|
||||||
|
|
||||||
# Add source domain information, required by qrexec-client for establishing
|
|
||||||
# connection
|
|
||||||
process_ident+=","+domain+","+domain_id
|
|
||||||
|
|
||||||
vm = validate_target(target)
|
|
||||||
if vm is None:
|
|
||||||
print >> sys.stderr, "Rpc failed (unknown domain):", domain, target, service_name
|
|
||||||
text = "Domain '%s' doesn't exist (service %s called by domain %s)." % (
|
|
||||||
target, service_name, domain)
|
|
||||||
info_dialog("error", text)
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
policy_list=read_policy_file(service_name)
|
|
||||||
if policy_list==None:
|
|
||||||
policy_editor(domain, target, service_name)
|
|
||||||
policy_list=read_policy_file(service_name)
|
|
||||||
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, service_name)
|
|
||||||
if user_choice == UserChoice.ALWAYS_ALLOW:
|
|
||||||
add_always_allow(domain, target, service_name, 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, service_name
|
|
||||||
do_execute(domain, target, user, service_name, process_ident, vm=vm)
|
|
||||||
|
|
||||||
print >> sys.stderr, "Rpc denied:", domain, target, service_name
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
main()
|
|
@ -47,6 +47,7 @@ BuildRequires: qubes-utils-devel >= 3.1.3
|
|||||||
BuildRequires: qubes-libvchan-devel
|
BuildRequires: qubes-libvchan-devel
|
||||||
Requires: qubes-core-dom0
|
Requires: qubes-core-dom0
|
||||||
Requires: qubes-utils >= 3.1.3
|
Requires: qubes-utils >= 3.1.3
|
||||||
|
Requires: python3-PyQt4
|
||||||
Requires: %{name}-kernel-install
|
Requires: %{name}-kernel-install
|
||||||
Requires: xdotool
|
Requires: xdotool
|
||||||
|
|
||||||
@ -76,8 +77,6 @@ ln -sf . %{name}-%{version}
|
|||||||
%setup -T -D
|
%setup -T -D
|
||||||
|
|
||||||
%build
|
%build
|
||||||
python -m compileall appmenus-scripts
|
|
||||||
python -O -m compileall appmenus-scripts
|
|
||||||
(cd dom0-updates; make)
|
(cd dom0-updates; make)
|
||||||
(cd qrexec; make)
|
(cd qrexec; make)
|
||||||
(cd file-copy-vm; make)
|
(cd file-copy-vm; make)
|
||||||
@ -85,25 +84,9 @@ python -O -m compileall appmenus-scripts
|
|||||||
|
|
||||||
%install
|
%install
|
||||||
|
|
||||||
### Appmenus
|
## Appmenus
|
||||||
|
install -d $RPM_BUILD_ROOT/etc/qubes-rpc/policy
|
||||||
mkdir -p $RPM_BUILD_ROOT%{python_sitearch}/qubes/modules
|
cp qubesappmenus/qubes.SyncAppMenus.policy $RPM_BUILD_ROOT/etc/qubes-rpc/policy/qubes.SyncAppMenus
|
||||||
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
|
### 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-updates.cron $RPM_BUILD_ROOT/etc/cron.daily/qubes-dom0-updates.cron
|
||||||
@ -118,12 +101,12 @@ install -m 0664 -D dom0-updates/qubes.ReceiveUpdates.policy $RPM_BUILD_ROOT/etc/
|
|||||||
install -d $RPM_BUILD_ROOT/var/lib/qubes/updates
|
install -d $RPM_BUILD_ROOT/var/lib/qubes/updates
|
||||||
|
|
||||||
# Qrexec
|
# Qrexec
|
||||||
mkdir -p $RPM_BUILD_ROOT/usr/lib/qubes/
|
mkdir -p $RPM_BUILD_ROOT/usr/bin $RPM_BUILD_ROOT/usr/sbin
|
||||||
cp qrexec/qrexec-daemon $RPM_BUILD_ROOT/usr/lib/qubes/
|
install qrexec/qrexec-daemon $RPM_BUILD_ROOT/usr/sbin/
|
||||||
cp qrexec/qrexec-client $RPM_BUILD_ROOT/usr/lib/qubes/
|
install qrexec/qrexec-client $RPM_BUILD_ROOT/usr/bin/
|
||||||
# XXX: Backward compatibility
|
# XXX: Backward compatibility
|
||||||
ln -s qrexec-client $RPM_BUILD_ROOT/usr/lib/qubes/qrexec_client
|
ln -s ../../bin/qrexec-client $RPM_BUILD_ROOT/usr/lib/qubes/qrexec-client
|
||||||
cp qrexec/qrexec-policy $RPM_BUILD_ROOT/usr/lib/qubes/
|
ln -s ../../sbin/qrexec-daemon $RPM_BUILD_ROOT/usr/lib/qubes/qrexec-daemon
|
||||||
cp qrexec/qubes-rpc-multiplexer $RPM_BUILD_ROOT/usr/lib/qubes
|
cp qrexec/qubes-rpc-multiplexer $RPM_BUILD_ROOT/usr/lib/qubes
|
||||||
|
|
||||||
### pm-utils
|
### pm-utils
|
||||||
@ -167,12 +150,6 @@ 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-to-vm $RPM_BUILD_ROOT/usr/bin/
|
||||||
ln -s qvm-copy-to-vm $RPM_BUILD_ROOT/usr/bin/qvm-move-to-vm
|
ln -s qvm-copy-to-vm $RPM_BUILD_ROOT/usr/bin/qvm-move-to-vm
|
||||||
|
|
||||||
### 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
|
### Documentation
|
||||||
(cd doc; make DESTDIR=$RPM_BUILD_ROOT install)
|
(cd doc; make DESTDIR=$RPM_BUILD_ROOT install)
|
||||||
|
|
||||||
@ -183,13 +160,6 @@ fi
|
|||||||
|
|
||||||
%post
|
%post
|
||||||
|
|
||||||
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-*.desktop
|
|
||||||
|
|
||||||
/usr/lib/qubes/patch-dnf-yum-config
|
/usr/lib/qubes/patch-dnf-yum-config
|
||||||
|
|
||||||
systemctl enable qubes-suspend.service >/dev/null 2>&1
|
systemctl enable qubes-suspend.service >/dev/null 2>&1
|
||||||
@ -198,12 +168,6 @@ systemctl enable qubes-suspend.service >/dev/null 2>&1
|
|||||||
if [ "$1" = 0 ] ; then
|
if [ "$1" = 0 ] ; then
|
||||||
# no more packages left
|
# 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-*.desktop
|
|
||||||
|
|
||||||
systemctl disable qubes-suspend.service > /dev/null 2>&1
|
systemctl disable qubes-suspend.service > /dev/null 2>&1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -219,29 +183,7 @@ rm -f /lib/udev/rules.d/69-xorg-vmmouse.rules
|
|||||||
chmod -x /etc/grub.d/10_linux
|
chmod -x /etc/grub.d/10_linux
|
||||||
|
|
||||||
%files
|
%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/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-xterm.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
|
# Dom0 updates
|
||||||
/etc/cron.daily/qubes-dom0-updates.cron
|
/etc/cron.daily/qubes-dom0-updates.cron
|
||||||
/etc/yum.real.repos.d/qubes-cached.repo
|
/etc/yum.real.repos.d/qubes-cached.repo
|
||||||
@ -259,11 +201,12 @@ chmod -x /etc/grub.d/10_linux
|
|||||||
%dir %{_dracutmoddir}/90extra-modules
|
%dir %{_dracutmoddir}/90extra-modules
|
||||||
%{_dracutmoddir}/90extra-modules/*
|
%{_dracutmoddir}/90extra-modules/*
|
||||||
# Qrexec
|
# Qrexec
|
||||||
%attr(4750,root,qubes) /usr/lib/qubes/qrexec-daemon
|
/usr/sbin/qrexec-daemon
|
||||||
/usr/lib/qubes/qrexec-client
|
/usr/bin/qrexec-client
|
||||||
/usr/lib/qubes/qrexec_client
|
|
||||||
/usr/lib/qubes/qubes-rpc-multiplexer
|
/usr/lib/qubes/qubes-rpc-multiplexer
|
||||||
/usr/lib/qubes/qrexec-policy
|
# compat symlinks
|
||||||
|
/usr/lib/qubes/qrexec-client
|
||||||
|
/usr/lib/qubes/qrexec-daemon
|
||||||
# file copy
|
# file copy
|
||||||
/usr/bin/qvm-copy-to-vm
|
/usr/bin/qvm-copy-to-vm
|
||||||
/usr/bin/qvm-move-to-vm
|
/usr/bin/qvm-move-to-vm
|
||||||
|
@ -28,6 +28,7 @@ enable xenstored.service
|
|||||||
enable xenstored.socket
|
enable xenstored.socket
|
||||||
enable xenstored_ro.socket
|
enable xenstored_ro.socket
|
||||||
enable xenconsoled.service
|
enable xenconsoled.service
|
||||||
|
enable xen-init-dom0.service
|
||||||
enable libvirtd.service
|
enable libvirtd.service
|
||||||
enable virlockd.socket
|
enable virlockd.socket
|
||||||
|
|
||||||
@ -45,6 +46,7 @@ enable qubes-qmemman.service
|
|||||||
enable qubes-suspend.service
|
enable qubes-suspend.service
|
||||||
enable qubes-setupdvm.service
|
enable qubes-setupdvm.service
|
||||||
enable qubes-block-cleaner.service
|
enable qubes-block-cleaner.service
|
||||||
|
enable qubesd.service
|
||||||
enable anti-evil-maid-unseal.service
|
enable anti-evil-maid-unseal.service
|
||||||
enable anti-evil-maid-check-mount-devs.service
|
enable anti-evil-maid-check-mount-devs.service
|
||||||
enable anti-evil-maid-seal.service
|
enable anti-evil-maid-seal.service
|
||||||
|