Remove core2 code

This all either have been migrated to core3, or is not needed anymore.

There is still qvm-tools directory with a few tools that needs to be
migrated, or installed as is.
This commit is contained in:
Marek Marczykowski-Górecki 2017-05-11 20:30:05 +02:00
parent bb4dc91ee8
commit 8992e71f85
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
51 changed files with 0 additions and 7220 deletions

View File

@ -40,16 +40,10 @@ rpms-dom0:
$(RPMS_DIR)/x86_64/qubes-core-dom0-$(VERSION)*.rpm \
$(RPMS_DIR)/noarch/qubes-core-dom0-doc-$(VERSION)*rpm
clean:
make -C dispvm clean
all:
$(PYTHON) setup.py build
# make all -C tests
# Currently supported only on xen
ifeq ($(BACKEND_VMM),xen)
make all -C dispvm
endif
install:
ifeq ($(OS),Linux)
@ -67,7 +61,6 @@ ifeq ($(BACKEND_VMM),xen)
# Currently supported only on xen
cp etc/qmemman.conf $(DESTDIR)/etc/qubes/
endif
$(MAKE) install -C dispvm
mkdir -p $(DESTDIR)/etc/qubes-rpc/policy
mkdir -p $(DESTDIR)/usr/libexec/qubes
cp qubes-rpc-policy/qubes.FeaturesRequest.policy $(DESTDIR)/etc/qubes-rpc/policy/qubes.FeaturesRequest

File diff suppressed because it is too large Load Diff

View File

@ -1,77 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# 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.
#
#
from __future__ import (
absolute_import,
division,
print_function,
unicode_literals,
)
from qubes.qubes import (
register_qubes_vm_class,
QubesException,
QubesVm,
)
from time import sleep
class QubesResizableVm(QubesVm):
def resize_root_img(self, size, allow_start=False):
if self.template:
raise QubesException("Cannot resize root.img of template-based VM"
". Resize the root.img of the template "
"instead.")
if self.is_running():
raise QubesException("Cannot resize root.img of running VM")
if size < self.get_root_img_sz():
raise QubesException(
"For your own safety shringing of root.img is disabled. If "
"you really know what you are doing, use 'truncate' manually.")
f_root = open(self.root_img, "a+b")
f_root.truncate(size)
f_root.close()
class QubesResizableVmWithResize2fs(QubesResizableVm):
def resize_root_img(self, size, allow_start=False):
super(QubesResizableVmWithResize2fs, self).\
resize_root_img(size, allow_start=allow_start)
if not allow_start:
raise QubesException("VM start required to complete the "
"operation, but not allowed. Either run the "
"operation again allowing VM start this "
"time, or run resize2fs in the VM manually.")
self.start(start_guid=False)
self.run("resize2fs /dev/mapper/dmroot", user="root", wait=True,
gui=False)
self.shutdown()
while self.is_running():
sleep(1)
register_qubes_vm_class(QubesResizableVm)
register_qubes_vm_class(QubesResizableVmWithResize2fs)

View File

@ -1,54 +0,0 @@
#!/usr/bin/python2
# -*- coding: utf-8 -*-
#
# 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 os.path
from qubes.qubes import (
register_qubes_vm_class,
system_path,
QubesResizableVmWithResize2fs,
QubesVmLabel,
)
class QubesAppVm(QubesResizableVmWithResize2fs):
"""
A class that represents an AppVM. A child of QubesVm.
"""
def get_attrs_config(self):
attrs_config = super(QubesAppVm, self).get_attrs_config()
attrs_config['dir_path']['func'] = \
lambda value: value if value is not None else \
os.path.join(system_path["qubes_appvms_dir"], self.name)
return attrs_config
@property
def type(self):
return "AppVM"
def is_appvm(self):
return True
register_qubes_vm_class(QubesAppVm)

View File

@ -1,248 +0,0 @@
#!/usr/bin/python2
# -*- coding: utf-8 -*-
#
# 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 os
import sys
import libvirt
import time
from qubes.qubes import QubesVm,QubesVmLabel,register_qubes_vm_class, \
QubesException
from qubes.qubes import QubesDispVmLabels
from qubes.qubes import dry_run,vmm
import grp
qmemman_present = False
try:
from qubes.qmemman_client import QMemmanClient
qmemman_present = True
except ImportError:
pass
DISPID_STATE_FILE = '/var/run/qubes/dispid'
GUID_SHMID_FILE = ['/var/run/qubes/shm.id', '/var/run/shm.id']
class QubesDisposableVm(QubesVm):
"""
A class that represents an DisposableVM. A child of QubesVm.
"""
# In which order load this VM type from qubes.xml
load_order = 120
def _assign_new_dispid(self):
# This method in called while lock on qubes.xml is held, so no need for
# additional lock
if os.path.exists(DISPID_STATE_FILE):
f = open(DISPID_STATE_FILE, 'r+')
dispid = int(f.read())
f.seek(0)
f.truncate(0)
f.write(str(dispid+1))
f.close()
else:
dispid = 1
f = open(DISPID_STATE_FILE, 'w')
f.write(str(dispid+1))
f.close()
os.chown(DISPID_STATE_FILE, -1, grp.getgrnam('qubes').gr_gid)
os.chmod(DISPID_STATE_FILE, 0664)
return dispid
def get_attrs_config(self):
attrs_config = super(QubesDisposableVm, self).get_attrs_config()
attrs_config['name']['func'] = \
lambda x: "disp%d" % self.dispid if x is None else x
# New attributes
attrs_config['dispid'] = {
'func': lambda x: (self._assign_new_dispid() if x is None
else int(x)),
'save': lambda: str(self.dispid),
# needs to be set before name
'order': 0
}
attrs_config['include_in_backups']['func'] = lambda x: False
attrs_config['disp_savefile'] = {
'default': '/var/run/qubes/current-savefile',
'save': lambda: str(self.disp_savefile) }
return attrs_config
def __init__(self, **kwargs):
disp_template = None
if 'disp_template' in kwargs.keys():
disp_template = kwargs['disp_template']
kwargs['template'] = disp_template.template
kwargs['dir_path'] = disp_template.dir_path
kwargs['kernel'] = disp_template.kernel
kwargs['uses_default_kernel'] = disp_template.uses_default_kernel
kwargs['kernelopts'] = disp_template.kernelopts
kwargs['uses_default_kernelopts'] = \
disp_template.uses_default_kernelopts
super(QubesDisposableVm, self).__init__(**kwargs)
assert self.template is not None, "Missing template for DisposableVM!"
if disp_template:
self.clone_attrs(disp_template)
# Use DispVM icon with the same color
if self._label:
self._label = QubesDispVmLabels[self._label.name]
self.icon_path = self._label.icon_path
@property
def type(self):
return "DisposableVM"
def is_disposablevm(self):
return True
@property
def ip(self):
if self.netvm is not None:
return self.netvm.get_ip_for_dispvm(self.dispid)
else:
return None
def get_clone_attrs(self):
attrs = super(QubesDisposableVm, self).get_clone_attrs()
attrs.remove('_label')
return attrs
def do_not_use_get_xml_attrs(self):
# Minimal set - do not inherit rest of attributes
attrs = {}
attrs["qid"] = str(self.qid)
attrs["name"] = self.name
attrs["dispid"] = str(self.dispid)
attrs["template_qid"] = str(self.template.qid)
attrs["label"] = self.label.name
attrs["firewall_conf"] = self.relative_path(self.firewall_conf)
attrs["netvm_qid"] = str(self.netvm.qid) if self.netvm is not None else "none"
return attrs
def verify_files(self):
return True
def get_config_params(self):
attrs = super(QubesDisposableVm, self).get_config_params()
attrs['privatedev'] = ''
return attrs
def create_qubesdb_entries(self):
super(QubesDisposableVm, self).create_qubesdb_entries()
self.qdb.write("/qubes-vm-persistence", "none")
self.qdb.write('/qubes-restore-complete', '1')
def start(self, verbose = False, **kwargs):
self.log.debug('start()')
if dry_run:
return
# Intentionally not used is_running(): eliminate also "Paused", "Crashed", "Halting"
if self.get_power_state() != "Halted":
raise QubesException ("VM is already running!")
if self.netvm is not None:
if self.netvm.qid != 0:
if not self.netvm.is_running():
if verbose:
print >> sys.stderr, "--> Starting NetVM {0}...".\
format(self.netvm.name)
self.netvm.start(verbose=verbose, **kwargs)
if verbose:
print >> sys.stderr, "--> Loading the VM (type = {0})...".format(self.type)
print >>sys.stderr, "time=%s, creating config file" % (str(time.time()))
# refresh config file
domain_config = self.create_config_file()
qmemman_client = self.request_memory()
# dispvm cannot have PCI devices
assert (len(self.pcidevs) == 0), "DispVM cannot have PCI devices"
print >>sys.stderr, "time=%s, calling restore" % (str(time.time()))
vmm.libvirt_conn.restoreFlags(self.disp_savefile,
domain_config, libvirt.VIR_DOMAIN_SAVE_PAUSED)
print >>sys.stderr, "time=%s, done" % (str(time.time()))
self._libvirt_domain = None
if verbose:
print >> sys.stderr, "--> Starting Qubes DB..."
self.start_qubesdb()
self.services['qubes-dvm'] = True
if verbose:
print >> sys.stderr, "--> Setting Qubes DB info for the VM..."
self.create_qubesdb_entries()
print >>sys.stderr, "time=%s, done qubesdb" % (str(time.time()))
# fire hooks
for hook in self.hooks_start:
hook(self, verbose = verbose, **kwargs)
if verbose:
print >> sys.stderr, "--> Starting the VM..."
self.libvirt_domain.resume()
print >>sys.stderr, "time=%s, resumed" % (str(time.time()))
# close() is not really needed, because the descriptor is close-on-exec
# anyway, the reason to postpone close() is that possibly xl is not done
# constructing the domain after its main process exits
# so we close() when we know the domain is up
# the successful unpause is some indicator of it
if qmemman_present:
qmemman_client.close()
if kwargs.get('start_guid', True) and \
any(os.path.exists(x) for x in GUID_SHMID_FILE):
self.start_guid(verbose=verbose, before_qrexec=True,
notify_function=kwargs.get('notify_function', None))
self.start_qrexec_daemon(verbose=verbose,
notify_function=kwargs.get('notify_function', None))
print >>sys.stderr, "time=%s, qrexec done" % (str(time.time()))
if kwargs.get('start_guid', True) and \
any(os.path.exists(x) for x in GUID_SHMID_FILE):
self.start_guid(verbose=verbose,
notify_function=kwargs.get('notify_function', None))
print >>sys.stderr, "time=%s, guid done" % (str(time.time()))
return self.xid
def remove_from_disk(self):
# nothing to remove
pass
# register classes
register_qubes_vm_class(QubesDisposableVm)

View File

@ -1,283 +0,0 @@
#!/usr/bin/python2
# -*- coding: utf-8 -*-
#
# 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 os
import os.path
import signal
import subprocess
import sys
import shutil
from xml.etree import ElementTree
from qubes.qubes import (
dry_run,
defaults,
register_qubes_vm_class,
system_path,
vmm,
QubesException,
QubesResizableVm,
)
system_path["config_template_hvm"] = '/usr/share/qubes/vm-template-hvm.xml'
defaults["hvm_disk_size"] = 20*1024*1024*1024
defaults["hvm_private_img_size"] = 2*1024*1024*1024
defaults["hvm_memory"] = 512
class QubesHVm(QubesResizableVm):
"""
A class that represents an HVM. A child of QubesVm.
"""
# FIXME: logically should inherit after QubesAppVm, but none of its methods
# are useful for HVM
def get_attrs_config(self):
attrs = super(QubesHVm, self).get_attrs_config()
attrs.pop('kernel')
attrs.pop('kernels_dir')
attrs.pop('kernelopts')
attrs.pop('uses_default_kernel')
attrs.pop('uses_default_kernelopts')
attrs['dir_path']['func'] = lambda value: value if value is not None \
else os.path.join(system_path["qubes_appvms_dir"], self.name)
attrs['config_file_template']['func'] = \
lambda x: system_path["config_template_hvm"]
attrs['drive'] = { 'attr': '_drive',
'save': lambda: str(self.drive) }
# Remove this two lines when HVM will get qmemman support
attrs['maxmem'].pop('save')
attrs['maxmem']['func'] = lambda x: self.memory
attrs['timezone'] = { 'default': 'localtime',
'save': lambda: str(self.timezone) }
attrs['qrexec_installed'] = { 'default': False,
'attr': '_qrexec_installed',
'save': lambda: str(self._qrexec_installed) }
attrs['guiagent_installed'] = { 'default' : False,
'attr': '_guiagent_installed',
'save': lambda: str(self._guiagent_installed) }
attrs['seamless_gui_mode'] = { 'default': False,
'attr': '_seamless_gui_mode',
'save': lambda: str(self._seamless_gui_mode) }
attrs['services']['default'] = "{'meminfo-writer': False}"
return attrs
@classmethod
def is_template_compatible(cls, template):
if template and (not template.is_template() or template.type != "TemplateHVM"):
return False
return True
def get_clone_attrs(self):
attrs = super(QubesHVm, self).get_clone_attrs()
attrs.remove('kernel')
attrs.remove('uses_default_kernel')
attrs.remove('kernelopts')
attrs.remove('uses_default_kernelopts')
attrs += [ 'timezone' ]
attrs += [ 'qrexec_installed' ]
attrs += [ 'guiagent_installed' ]
return attrs
@property
def seamless_gui_mode(self):
if not self.guiagent_installed:
return False
return self._seamless_gui_mode
@seamless_gui_mode.setter
def seamless_gui_mode(self, value):
if self._seamless_gui_mode == value:
return
if not self.guiagent_installed and value:
raise ValueError("Seamless GUI mode requires GUI agent installed")
self._seamless_gui_mode = value
if self.is_running():
self.send_gui_mode()
@property
def drive(self):
return self._drive
@drive.setter
def drive(self, value):
if value is None:
self._drive = None
return
# strip type for a moment
drv_type = "cdrom"
if value.startswith("hd:") or value.startswith("cdrom:"):
(drv_type, unused, value) = value.partition(":")
drv_type = drv_type.lower()
# sanity check
if drv_type not in ['hd', 'cdrom']:
raise QubesException("Unsupported drive type: %s" % type)
if value.count(":") == 0:
value = "dom0:" + value
if value.count(":/") == 0:
# FIXME: when Windows backend will be supported, improve this
raise QubesException("Drive path must be absolute")
self._drive = drv_type + ":" + value
def create_on_disk(self, verbose, source_template = None):
self.log.debug('create_on_disk(source_template={!r})'.format(
source_template))
if dry_run:
return
if source_template is None:
source_template = self.template
# create empty disk
self.storage.private_img_size = defaults["hvm_private_img_size"]
self.storage.root_img_size = defaults["hvm_disk_size"]
self.storage.create_on_disk(verbose, source_template)
if verbose:
print >> sys.stderr, "--> Creating icon symlink: {0} -> {1}".format(self.icon_path, self.label.icon_path)
try:
if hasattr(os, "symlink"):
os.symlink (self.label.icon_path, self.icon_path)
else:
shutil.copy(self.label.icon_path, self.icon_path)
except Exception as e:
print >> sys.stderr, "WARNING: Failed to set VM icon: %s" % str(e)
# Make sure that we have UUID allocated
self._update_libvirt_domain()
# fire hooks
for hook in self.hooks_create_on_disk:
hook(self, verbose, source_template=source_template)
def get_private_img_sz(self):
if not os.path.exists(self.private_img):
return 0
return os.path.getsize(self.private_img)
def resize_private_img(self, size):
assert size >= self.get_private_img_sz(), "Cannot shrink private.img"
if self.is_running():
raise NotImplementedError("Online resize of HVM's private.img not implemented, shutdown the VM first")
self.storage.resize_private_img(size)
def run(self, command, **kwargs):
if self.qrexec_installed:
if 'gui' in kwargs and kwargs['gui']==False:
command = "nogui:" + command
return super(QubesHVm, self).run(command, **kwargs)
else:
raise QubesException("Needs qrexec agent installed in VM to use this function. See also qvm-prefs.")
@property
def stubdom_xid(self):
if self.xid < 0:
return -1
if vmm.xs is None:
return -1
stubdom_xid_str = vmm.xs.read('', '/local/domain/%d/image/device-model-domid' % self.xid)
if stubdom_xid_str is not None:
return int(stubdom_xid_str)
else:
return -1
def validate_drive_path(self, drive):
drive_type, drive_domain, drive_path = drive.split(':', 2)
if drive_domain == 'dom0':
if not os.path.exists(drive_path):
raise QubesException("Invalid drive path '{}'".format(
drive_path))
def start(self, *args, **kwargs):
if self.drive:
self.validate_drive_path(self.drive)
# make it available to storage.prepare_for_vm_startup, which is
# called before actually building VM libvirt configuration
self.storage.drive = self.drive
if self.template and self.template.is_running():
raise QubesException("Cannot start the HVM while its template is running")
try:
if 'mem_required' not in kwargs:
# Reserve 44MB for stubdomain
kwargs['mem_required'] = (self.memory + 44) * 1024 * 1024
return super(QubesHVm, self).start(*args, **kwargs)
except QubesException as e:
capabilities = vmm.libvirt_conn.getCapabilities()
tree = ElementTree.fromstring(capabilities)
os_types = tree.findall('./guest/os_type')
if 'hvm' not in map(lambda x: x.text, os_types):
raise QubesException("Cannot start HVM without VT-x/AMD-v enabled")
else:
raise
def _cleanup_zombie_domains(self):
super(QubesHVm, self)._cleanup_zombie_domains()
if not self.is_running():
xc_stubdom = self.get_xc_dominfo(name=self.name+'-dm')
if xc_stubdom is not None:
if xc_stubdom['paused'] == 1:
subprocess.call(['xl', 'destroy', str(xc_stubdom['domid'])])
if xc_stubdom['dying'] == 1:
# GUID still running?
guid_pidfile = \
'/var/run/qubes/guid-running.%d' % xc_stubdom['domid']
if os.path.exists(guid_pidfile):
guid_pid = open(guid_pidfile).read().strip()
os.kill(int(guid_pid), 15)
def is_guid_running(self):
# If user force the guiagent, is_guid_running will mimic a standard QubesVM
if self.guiagent_installed:
return super(QubesHVm, self).is_guid_running()
else:
xid = self.stubdom_xid
if xid < 0:
return False
if not os.path.exists('/var/run/qubes/guid-running.%d' % xid):
return False
return True
def is_fully_usable(self):
# Running gui-daemon implies also VM running
if not self.is_guid_running():
return False
if self.qrexec_installed and not self.is_qrexec_running():
return False
return True

View File

@ -1,110 +0,0 @@
#!/usr/bin/python2
# -*- coding: utf-8 -*-
#
# 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 os
import os.path
import subprocess
import stat
import sys
import re
from qubes.qubes import QubesHVm,register_qubes_vm_class,dry_run,vmm
from qubes.qubes import QubesException,QubesVmCollection
from qubes.qubes import system_path,defaults
class QubesTemplateHVm(QubesHVm):
"""
A class that represents an HVM template. A child of QubesHVm.
"""
# In which order load this VM type from qubes.xml
load_order = 50
def get_attrs_config(self):
attrs_config = super(QubesTemplateHVm, self).get_attrs_config()
attrs_config['dir_path']['func'] = \
lambda value: value if value is not None else \
os.path.join(system_path["qubes_templates_dir"], self.name)
attrs_config['label']['default'] = defaults["template_label"]
return attrs_config
def __init__(self, **kwargs):
super(QubesTemplateHVm, self).__init__(**kwargs)
self.appvms = QubesVmCollection()
@property
def type(self):
return "TemplateHVM"
@property
def updateable(self):
return True
def is_template(self):
return True
def is_appvm(self):
return False
@property
def rootcow_img(self):
return self.storage.rootcow_img
@classmethod
def is_template_compatible(cls, template):
if template is None:
return True
return False
def resize_root_img(self, size):
for vm in self.appvms.values():
if vm.is_running():
raise QubesException("Cannot resize root.img while any VM "
"based on this tempate is running")
return super(QubesTemplateHVm, self).resize_root_img(size)
def start(self, *args, **kwargs):
for vm in self.appvms.values():
if vm.is_running():
raise QubesException("Cannot start HVM template while VMs based on it are running")
return super(QubesTemplateHVm, self).start(*args, **kwargs)
def commit_changes (self, verbose = False):
self.log.debug('commit_changes()')
if not vmm.offline_mode:
assert not self.is_running(), "Attempt to commit changes on running Template VM!"
if verbose:
print >> sys.stderr, "--> Commiting template updates... COW: {0}...".format (self.rootcow_img)
if dry_run:
return
self.storage.commit_template_changes()
register_qubes_vm_class(QubesTemplateHVm)

View File

@ -1,15 +0,0 @@
PYTHON_QUBESMODPATH = $(PYTHON_SITEPATH)/qubes/modules
all:
python -m compileall .
python -O -m compileall .
install:
ifndef PYTHON_SITEPATH
$(error PYTHON_SITEPATH not defined)
endif
mkdir -p $(DESTDIR)$(PYTHON_QUBESMODPATH)
cp 0*.py $(DESTDIR)$(PYTHON_QUBESMODPATH)
cp 0*.py[co] $(DESTDIR)$(PYTHON_QUBESMODPATH)
cp __init__.py $(DESTDIR)$(PYTHON_QUBESMODPATH)
cp __init__.py[co] $(DESTDIR)$(PYTHON_QUBESMODPATH)

View File

@ -1,5 +0,0 @@
This directory contains Qubes core modules. It will be loaded in
lexicographical order, use numeric prefix to force load ordering.
0* - Qubes base modules
00* - Qubes core VM classes

1
core/.gitignore vendored
View File

@ -1 +0,0 @@
*.pyo

View File

@ -1,31 +0,0 @@
OS ?= Linux
PYTHON_QUBESPATH = $(PYTHON_SITEPATH)/qubes
SETTINGS_SUFFIX = $(BACKEND_VMM)-$(OS)
all:
python -m compileall .
python -O -m compileall .
make -C storage all
install:
ifndef PYTHON_SITEPATH
$(error PYTHON_SITEPATH not defined)
endif
mkdir -p $(DESTDIR)$(PYTHON_QUBESPATH)
cp qubes.py $(DESTDIR)$(PYTHON_QUBESPATH)
cp qubes.py[co] $(DESTDIR)$(PYTHON_QUBESPATH)
cp qubesutils.py $(DESTDIR)$(PYTHON_QUBESPATH)
cp qubesutils.py[co] $(DESTDIR)$(PYTHON_QUBESPATH)
cp guihelpers.py $(DESTDIR)$(PYTHON_QUBESPATH)
cp guihelpers.py[co] $(DESTDIR)$(PYTHON_QUBESPATH)
cp backup.py $(DESTDIR)$(PYTHON_QUBESPATH)
cp backup.py[co] $(DESTDIR)$(PYTHON_QUBESPATH)
ifneq ($(BACKEND_VMM),)
if [ -r settings-$(SETTINGS_SUFFIX).py ]; then \
cp settings-$(SETTINGS_SUFFIX).py $(DESTDIR)$(PYTHON_QUBESPATH)/settings.py && \
cp settings-$(SETTINGS_SUFFIX).pyc $(DESTDIR)$(PYTHON_QUBESPATH)/settings.pyc && \
cp settings-$(SETTINGS_SUFFIX).pyo $(DESTDIR)$(PYTHON_QUBESPATH)/settings.pyo; \
fi
endif
make -C storage install

View File

View File

@ -1,57 +0,0 @@
#!/usr/bin/python2
# -*- coding: utf-8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2011 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 sys
from optparse import OptionParser
from PyQt4.QtGui import QApplication,QMessageBox
app = None
system_bus = None
def prepare_app():
global app
app = QApplication(sys.argv)
app.setOrganizationName("The Qubes Project")
app.setOrganizationDomain("http://qubes-os.org")
app.setApplicationName("Qubes")
def ask(text, title="Question", yestoall=False):
global app
if app is None:
prepare_app()
buttons = QMessageBox.Yes | QMessageBox.No
if yestoall:
buttons |= QMessageBox.YesToAll
reply = QMessageBox.question(None, title, text, buttons, defaultButton=QMessageBox.Yes)
if reply == QMessageBox.Yes:
return 0
elif reply == QMessageBox.No:
return 1
elif reply == QMessageBox.YesToAll:
return 2
else:
#?!
return 127

View File

@ -1 +0,0 @@
../core-modules

View File

@ -1,187 +0,0 @@
#!/usr/bin/python2
# -*- coding: utf-8 -*-
#
# 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.
#
#
qubes_base_dir = "/var/lib/qubes"
system_path = {
'qubes_guid_path': '/usr/bin/qubes-guid',
'qrexec_daemon_path': '/usr/lib/qubes/qrexec-daemon',
'qrexec_client_path': '/usr/lib/qubes/qrexec-client',
'qubesdb_daemon_path': '/usr/sbin/qubesdb-daemon',
'qubes_base_dir': qubes_base_dir,
# Relative to qubes_base_dir
'qubes_appvms_dir': 'appvms',
'qubes_templates_dir': 'vm-templates',
'qubes_servicevms_dir': 'servicevms',
'qubes_store_filename': 'qubes.xml',
'qubes_kernels_base_dir': 'vm-kernels',
# qubes_icon_dir is obsolete
# use QIcon.fromTheme() where applicable
'qubes_icon_dir': '/usr/share/icons/hicolor/128x128/devices',
'qrexec_policy_dir': '/etc/qubes-rpc/policy',
'config_template_pv': '/usr/share/qubes/vm-template.xml',
'qubes_pciback_cmd': '/usr/lib/qubes/unbind-pci-device.sh',
'prepare_volatile_img_cmd': '/usr/lib/qubes/prepare-volatile-img.sh',
}
vm_files = {
'root_img': 'root.img',
'rootcow_img': 'root-cow.img',
'volatile_img': 'volatile.img',
'private_img': 'private.img',
'kernels_subdir': 'kernels',
'firewall_conf': 'firewall.xml',
'whitelisted_appmenus': 'whitelisted-appmenus.list',
'updates_stat_file': 'updates.stat',
}
defaults = {
'libvirt_uri': 'xen:///',
'memory': 400,
'kernelopts': "nopat",
'kernelopts_pcidevs': "nopat iommu=soft swiotlb=8192",
'dom0_update_check_interval': 6*3600,
'private_img_size': 2*1024*1024*1024,
'root_img_size': 10*1024*1024*1024,
'storage_class': None,
# how long (in sec) to wait for VMs to shutdown,
# before killing them (when used qvm-run with --wait option),
'shutdown_counter_max': 60,
'vm_default_netmask': "255.255.255.0",
# Set later
'appvm_label': None,
'template_label': None,
'servicevm_label': None,
}
qubes_max_qid = 254
qubes_max_netid = 254
##########################################
def register_qubes_vm_class(vm_class):
QubesVmClasses[vm_class.__name__] = vm_class
# register class as local for this module - to make it easy to import from
# other modules
setattr(sys.modules[__name__], vm_class.__name__, vm_class)
class QubesDaemonPidfile(object):
def __init__(self, name):
self.name = name
self.path = "/var/run/qubes/" + name + ".pid"
def create_pidfile(self):
f = open (self.path, 'w')
f.write(str(os.getpid()))
f.close()
def pidfile_exists(self):
return os.path.exists(self.path)
def read_pid(self):
f = open (self.path)
pid = f.read ().strip()
f.close()
return int(pid)
def pidfile_is_stale(self):
if not self.pidfile_exists():
return False
# check if the pid file is valid...
proc_path = "/proc/" + str(self.read_pid()) + "/cmdline"
if not os.path.exists (proc_path):
print >> sys.stderr, \
"Path {0} doesn't exist, assuming stale pidfile.".\
format(proc_path)
return True
return False # It's a good pidfile
def remove_pidfile(self):
os.remove (self.path)
def __enter__ (self):
# assumes the pidfile doesn't exist -- you should ensure it before opening the context
self.create_pidfile()
def __exit__ (self, exc_type, exc_val, exc_tb):
self.remove_pidfile()
return False
### Initialization code
# Globally defined lables
QubesVmLabels = {
"red": QubesVmLabel(1, "0xcc0000", "red" ),
"orange": QubesVmLabel(2, "0xf57900", "orange" ),
"yellow": QubesVmLabel(3, "0xedd400", "yellow" ),
"green": QubesVmLabel(4, "0x73d216", "green" ),
"gray": QubesVmLabel(5, "0x555753", "gray" ),
"blue": QubesVmLabel(6, "0x3465a4", "blue" ),
"purple": QubesVmLabel(7, "0x75507b", "purple" ),
"black": QubesVmLabel(8, "0x000000", "black" ),
}
QubesDispVmLabels = {
k: QubesVmLabel(index=v.index, color=v.color, name=v.name, dispvm=True)
for k, v in QubesVmLabels.iteritems()
}
defaults["appvm_label"] = QubesVmLabels["red"]
defaults["template_label"] = QubesVmLabels["black"]
defaults["servicevm_label"] = QubesVmLabels["red"]
QubesVmClasses = {}
modules_dir = os.path.join(os.path.dirname(__file__), 'modules')
for module_file in sorted(os.listdir(modules_dir)):
if not module_file.endswith(".py") or module_file == "__init__.py":
continue
__import__('qubes.modules.%s' % module_file[:-3])
try:
import qubes.settings
qubes.settings.apply(system_path, vm_files, defaults)
except ImportError:
pass
for path_key in system_path.keys():
if not os.path.isabs(system_path[path_key]):
system_path[path_key] = os.path.join(
system_path['qubes_base_dir'], system_path[path_key])
# vim:sw=4:et:

View File

@ -1,844 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2011 Marek Marczykowski <marmarek@invisiblethingslab.com>
# Copyright (C) 2014 Wojciech Porczyk <wojciech@porczyk.eu>
#
# 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.
#
#
from __future__ import absolute_import
import string
import errno
from lxml import etree
from lxml.etree import ElementTree, SubElement, Element
from qubes.qubes import QubesException
from qubes.qubes import vmm,defaults
from qubes.qubes import system_path,vm_files
import sys
import os
import subprocess
import re
import time
import stat
import libvirt
from qubes.qdb import QubesDB,Error,DisconnectedError
import xen.lowlevel.xc
import xen.lowlevel.xs
# all frontends, prefer xvdi
# TODO: get this from libvirt driver?
AVAILABLE_FRONTENDS = ['xvd'+c for c in
string.lowercase[8:]+string.lowercase[:8]]
class USBProxyNotInstalled(QubesException):
pass
def mbytes_to_kmg(size):
if size > 1024:
return "%d GiB" % (size/1024)
else:
return "%d MiB" % size
def kbytes_to_kmg(size):
if size > 1024:
return mbytes_to_kmg(size/1024)
else:
return "%d KiB" % size
def bytes_to_kmg(size):
if size > 1024:
return kbytes_to_kmg(size/1024)
else:
return "%d B" % size
def size_to_human (size):
"""Humane readable size, with 1/10 precission"""
if size < 1024:
return str (size);
elif size < 1024*1024:
return str(round(size/1024.0,1)) + ' KiB'
elif size < 1024*1024*1024:
return str(round(size/(1024.0*1024),1)) + ' MiB'
else:
return str(round(size/(1024.0*1024*1024),1)) + ' GiB'
def print_stdout(text):
print (text)
def print_stderr(text):
print >> sys.stderr, (text)
###### Block devices ########
def block_devid_to_name(devid):
major = devid / 256
minor = devid % 256
dev_class = ""
if major == 202:
dev_class = "xvd"
elif major == 8:
dev_class = "sd"
else:
raise QubesException("Unknown device class %d" % major)
if minor % 16 == 0:
return "%s%c" % (dev_class, ord('a')+minor/16)
else:
return "%s%c%d" % (dev_class, ord('a')+minor/16, minor%16)
def block_name_to_majorminor(name):
# check if it is already devid
if isinstance(name, int):
return (name / 256, name % 256)
if name.isdigit():
return (int(name) / 256, int(name) % 256)
if os.path.exists('/dev/%s' % name):
blk_info = os.stat(os.path.realpath('/dev/%s' % name))
if stat.S_ISBLK(blk_info.st_mode):
return (blk_info.st_rdev / 256, blk_info.st_rdev % 256)
major = 0
minor = 0
dXpY_style = False
disk = True
if name.startswith("xvd"):
major = 202
elif name.startswith("sd"):
major = 8
elif name.startswith("mmcblk"):
dXpY_style = True
major = 179
elif name.startswith("scd"):
disk = False
major = 11
elif name.startswith("sr"):
disk = False
major = 11
elif name.startswith("loop"):
dXpY_style = True
disk = False
major = 7
elif name.startswith("md"):
dXpY_style = True
major = 9
elif name.startswith("dm-"):
disk = False
major = 253
else:
# Unknown device
return (0, 0)
if not dXpY_style:
name_match = re.match(r"^([a-z]+)([a-z-])([0-9]*)$", name)
else:
name_match = re.match(r"^([a-z]+)([0-9]*)(?:p([0-9]+))?$", name)
if not name_match:
raise QubesException("Invalid device name: %s" % name)
if disk:
if dXpY_style:
minor = int(name_match.group(2))*8
else:
minor = (ord(name_match.group(2))-ord('a')) * 16
else:
minor = 0
if name_match.group(3):
minor += int(name_match.group(3))
return (major, minor)
def block_name_to_devid(name):
# check if it is already devid
if isinstance(name, int):
return name
if name.isdigit():
return int(name)
(major, minor) = block_name_to_majorminor(name)
return major << 8 | minor
def block_find_unused_frontend(vm = None):
assert vm is not None
assert vm.is_running()
xml = vm.libvirt_domain.XMLDesc()
parsed_xml = etree.fromstring(xml)
used = [target.get('dev', None) for target in
parsed_xml.xpath("//domain/devices/disk/target")]
for dev in AVAILABLE_FRONTENDS:
if dev not in used:
return dev
return None
def block_list_vm(vm, system_disks = False):
name_re = re.compile(r"^[a-z0-9-]{1,12}$")
device_re = re.compile(r"^[a-z0-9/-]{1,64}$")
# FIXME: any better idea of desc_re?
desc_re = re.compile(r"^.{1,255}$")
mode_re = re.compile(r"^[rw]$")
assert vm is not None
if not vm.is_running():
return []
devices_list = {}
try:
untrusted_devices = vm.qdb.multiread('/qubes-block-devices/')
except Error:
vm.refresh()
return {}
def get_dev_item(dev, item):
return untrusted_devices.get(
'/qubes-block-devices/%s/%s' % (dev, item),
None)
untrusted_devices_names = list(set(map(lambda x: x.split("/")[2],
untrusted_devices.keys())))
for untrusted_dev_name in untrusted_devices_names:
if name_re.match(untrusted_dev_name):
dev_name = untrusted_dev_name
untrusted_device_size = get_dev_item(dev_name, 'size')
untrusted_device_desc = get_dev_item(dev_name, 'desc')
untrusted_device_mode = get_dev_item(dev_name, 'mode')
untrusted_device_device = get_dev_item(dev_name, 'device')
if untrusted_device_desc is None or untrusted_device_mode is None\
or untrusted_device_size is None:
print >>sys.stderr, "Missing field in %s device parameters" %\
dev_name
continue
if untrusted_device_device is None:
untrusted_device_device = '/dev/' + dev_name
if not device_re.match(untrusted_device_device):
print >> sys.stderr, "Invalid %s device path in VM '%s'" % (
dev_name, vm.name)
continue
device_device = untrusted_device_device
if not untrusted_device_size.isdigit():
print >> sys.stderr, "Invalid %s device size in VM '%s'" % (
dev_name, vm.name)
continue
device_size = int(untrusted_device_size)
if not desc_re.match(untrusted_device_desc):
print >> sys.stderr, "Invalid %s device desc in VM '%s'" % (
dev_name, vm.name)
continue
device_desc = untrusted_device_desc
if not mode_re.match(untrusted_device_mode):
print >> sys.stderr, "Invalid %s device mode in VM '%s'" % (
dev_name, vm.name)
continue
device_mode = untrusted_device_mode
if not system_disks:
if vm.qid == 0 and device_desc.startswith(system_path[
"qubes_base_dir"]):
continue
visible_name = "%s:%s" % (vm.name, dev_name)
devices_list[visible_name] = {
"name": visible_name,
"vm": vm.name,
"device": device_device,
"size": device_size,
"desc": device_desc,
"mode": device_mode
}
return devices_list
def block_list(qvmc = None, vm = None, system_disks = False):
if vm is not None:
if not vm.is_running():
return []
else:
vm_list = [ vm ]
else:
if qvmc is None:
raise QubesException("You must pass either qvm or vm argument")
vm_list = qvmc.values()
devices_list = {}
for vm in vm_list:
devices_list.update(block_list_vm(vm, system_disks))
return devices_list
def block_check_attached(qvmc, device):
"""
@type qvmc: QubesVmCollection
"""
if qvmc is None:
# TODO: ValueError
raise QubesException("You need to pass qvmc argument")
for vm in qvmc.values():
if vm.qid == 0:
# Connecting devices to dom0 not supported
continue
if not vm.is_running():
continue
try:
libvirt_domain = vm.libvirt_domain
if libvirt_domain:
xml = libvirt_domain.XMLDesc()
else:
xml = None
except libvirt.libvirtError:
if vmm.libvirt_conn.virConnGetLastError()[0] == libvirt.VIR_ERR_NO_DOMAIN:
xml = None
else:
raise
if xml:
parsed_xml = etree.fromstring(xml)
disks = parsed_xml.xpath("//domain/devices/disk")
for disk in disks:
backend_name = 'dom0'
if disk.find('backenddomain') is not None:
backend_name = disk.find('backenddomain').get('name')
source = disk.find('source')
if disk.get('type') == 'file':
path = source.get('file')
elif disk.get('type') == 'block':
path = source.get('dev')
else:
# TODO: logger
print >>sys.stderr, "Unknown disk type '%s' attached to " \
"VM '%s'" % (source.get('type'),
vm.name)
continue
if backend_name == device['vm'] and (path == device['device']
or not path.startswith('/dev/') and path == device[
'desc']):
return {
"frontend": disk.find('target').get('dev'),
"vm": vm}
return None
def device_attach_check(vm, backend_vm, device, frontend, mode):
""" Checks all the parameters, dies on errors """
if not vm.is_running():
raise QubesException("VM %s not running" % vm.name)
if not backend_vm.is_running():
raise QubesException("VM %s not running" % backend_vm.name)
if device['mode'] == 'r' and mode == 'w':
raise QubesException("Cannot attach read-only device in read-write "
"mode")
def block_attach(qvmc, vm, device, frontend=None, mode="w", auto_detach=False, wait=True):
backend_vm = qvmc.get_vm_by_name(device['vm'])
device_attach_check(vm, backend_vm, device, frontend, mode)
if frontend is None:
frontend = block_find_unused_frontend(vm)
if frontend is None:
raise QubesException("No unused frontend found")
else:
# Check if any device attached at this frontend
xml = vm.libvirt_domain.XMLDesc()
parsed_xml = etree.fromstring(xml)
disks = parsed_xml.xpath("//domain/devices/disk/target[@dev='%s']" %
frontend)
if len(disks):
raise QubesException("Frontend %s busy in VM %s, detach it first" % (frontend, vm.name))
# Check if this device is attached to some domain
attached_vm = block_check_attached(qvmc, device)
if attached_vm:
if auto_detach:
block_detach(attached_vm['vm'], attached_vm['frontend'])
else:
raise QubesException("Device %s from %s already connected to VM "
"%s as %s" % (device['device'],
backend_vm.name, attached_vm['vm'], attached_vm['frontend']))
disk = Element("disk")
disk.set('type', 'block')
disk.set('device', 'disk')
SubElement(disk, 'driver').set('name', 'phy')
SubElement(disk, 'source').set('dev', device['device'])
SubElement(disk, 'target').set('dev', frontend)
if backend_vm.qid != 0:
SubElement(disk, 'backenddomain').set('name', device['vm'])
if mode == "r":
SubElement(disk, 'readonly')
vm.libvirt_domain.attachDevice(etree.tostring(disk, encoding='utf-8'))
try:
# trigger watches to update device status
# FIXME: this should be removed once libvirt will report such
# events itself
vm.qdb.write('/qubes-block-devices', '')
except Error:
pass
def block_detach(vm, frontend = "xvdi"):
xml = vm.libvirt_domain.XMLDesc()
parsed_xml = etree.fromstring(xml)
attached = parsed_xml.xpath("//domain/devices/disk")
for disk in attached:
if frontend is not None and disk.find('target').get('dev') != frontend:
# Not the device we are looking for
continue
if frontend is None:
# ignore system disks
if disk.find('domain') == None and \
disk.find('source').get('dev').startswith(system_path[
"qubes_base_dir"]):
continue
vm.libvirt_domain.detachDevice(etree.tostring(disk, encoding='utf-8'))
try:
# trigger watches to update device status
# FIXME: this should be removed once libvirt will report such
# events itself
vm.qdb.write('/qubes-block-devices', '')
except Error:
pass
def block_detach_all(vm):
""" Detach all non-system devices"""
block_detach(vm, None)
####### USB devices ######
usb_ver_re = re.compile(r"^(1|2)$")
usb_device_re = re.compile(r"^[0-9]+-[0-9]+(_[0-9]+)?$")
usb_port_re = re.compile(r"^$|^[0-9]+-[0-9]+(\.[0-9]+)?$")
usb_desc_re = re.compile(r"^[ -~]{1,255}$")
# should match valid VM name
usb_connected_to_re = re.compile(r"^[a-zA-Z][a-zA-Z0-9_.-]*$")
def usb_decode_device_from_qdb(qdb_encoded_device):
""" recover actual device name (xenstore doesn't allow dot in key names, so it was translated to underscore) """
return qdb_encoded_device.replace('_', '.')
def usb_encode_device_for_qdb(device):
""" encode actual device name (xenstore doesn't allow dot in key names, so translated it into underscore) """
return device.replace('.', '_')
def usb_list_vm(qvmc, vm):
if not vm.is_running():
return {}
try:
untrusted_devices = vm.qdb.multiread('/qubes-usb-devices/')
except Error:
vm.refresh()
return {}
def get_dev_item(dev, item):
return untrusted_devices.get(
'/qubes-usb-devices/%s/%s' % (dev, item),
None)
devices = {}
untrusted_devices_names = list(set(map(lambda x: x.split("/")[2],
untrusted_devices.keys())))
for untrusted_dev_name in untrusted_devices_names:
if usb_device_re.match(untrusted_dev_name):
dev_name = untrusted_dev_name
untrusted_device_desc = get_dev_item(dev_name, 'desc')
if not usb_desc_re.match(untrusted_device_desc):
print >> sys.stderr, "Invalid %s device desc in VM '%s'" % (
dev_name, vm.name)
continue
device_desc = untrusted_device_desc
untrusted_connected_to = get_dev_item(dev_name, 'connected-to')
if untrusted_connected_to:
if not usb_connected_to_re.match(untrusted_connected_to):
print >>sys.stderr, \
"Invalid %s device 'connected-to' in VM '%s'" % (
dev_name, vm.name)
continue
connected_to = qvmc.get_vm_by_name(untrusted_connected_to)
if connected_to is None:
print >>sys.stderr, \
"Device {} appears to be connected to {}, " \
"but such VM doesn't exist".format(
dev_name, untrusted_connected_to)
else:
connected_to = None
device = usb_decode_device_from_qdb(dev_name)
full_name = vm.name + ':' + device
devices[full_name] = {
'vm': vm,
'device': device,
'qdb_path': '/qubes-usb-devices/' + dev_name,
'name': full_name,
'desc': device_desc,
'connected-to': connected_to,
}
return devices
def usb_list(qvmc, vm=None):
"""
Returns a dictionary of USB devices (for PVUSB backends running in all VM).
The dictionary is keyed by 'name' (see below), each element is a dictionary itself:
vm = backend domain object
device = device ID
name = <backend-vm>:<device>
desc = description
"""
if vm is not None:
if not vm.is_running():
return {}
else:
vm_list = [vm]
else:
vm_list = qvmc.values()
devices_list = {}
for vm in vm_list:
devices_list.update(usb_list_vm(qvmc, vm))
return devices_list
def usb_check_attached(qvmc, device):
"""Reread device attachment status"""
vm = device['vm']
untrusted_connected_to = vm.qdb.read(
'{}/connected-to'.format(device['qdb_path']))
if untrusted_connected_to:
if not usb_connected_to_re.match(untrusted_connected_to):
raise QubesException(
"Invalid %s device 'connected-to' in VM '%s'" % (
device['device'], vm.name))
connected_to = qvmc.get_vm_by_name(untrusted_connected_to)
if connected_to is None:
print >>sys.stderr, \
"Device {} appears to be connected to {}, " \
"but such VM doesn't exist".format(
device['device'], untrusted_connected_to)
else:
connected_to = None
return connected_to
def usb_attach(qvmc, vm, device, auto_detach=False, wait=True):
if not vm.is_running():
raise QubesException("VM {} not running".format(vm.name))
if not device['vm'].is_running():
raise QubesException("VM {} not running".format(device['vm'].name))
connected_to = usb_check_attached(qvmc, device)
if connected_to:
if auto_detach:
usb_detach(qvmc, device)
else:
raise QubesException("Device {} already connected, to {}".format(
device['name'], connected_to
))
# set qrexec policy to allow this device
policy_line = '{} {} allow\n'.format(vm.name, device['vm'].name)
policy_path = '/etc/qubes-rpc/policy/qubes.USB+{}'.format(device['device'])
policy_exists = os.path.exists(policy_path)
if not policy_exists:
try:
fd = os.open(policy_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY)
with os.fdopen(fd, 'w') as f:
f.write(policy_line)
except OSError as e:
if e.errno == errno.EEXIST:
pass
else:
raise
else:
with open(policy_path, 'r+') as f:
policy = f.readlines()
policy.insert(0, policy_line)
f.truncate(0)
f.seek(0)
f.write(''.join(policy))
try:
# and actual attach
p = vm.run_service('qubes.USBAttach', passio_popen=True, user='root')
(stdout, stderr) = p.communicate(
'{} {}\n'.format(device['vm'].name, device['device']))
if p.returncode == 127:
raise USBProxyNotInstalled(
"qubes-usb-proxy not installed in the VM")
elif p.returncode != 0:
# TODO: sanitize and include stdout
sanitized_stderr = ''.join([c for c in stderr if ord(c) >= 0x20])
raise QubesException('Device attach failed: {}'.format(
sanitized_stderr))
finally:
# FIXME: there is a race condition here - some other process might
# modify the file in the meantime. This may result in unexpected
# denials, but will not allow too much
if not policy_exists:
os.unlink(policy_path)
else:
with open(policy_path, 'r+') as f:
policy = f.readlines()
policy.remove('{} {} allow\n'.format(vm.name, device['vm'].name))
f.truncate(0)
f.seek(0)
f.write(''.join(policy))
def usb_detach(qvmc, vm, device):
connected_to = usb_check_attached(qvmc, device)
# detect race conditions; there is still race here, but much smaller
if connected_to is None or connected_to.qid != vm.qid:
raise QubesException(
"Device {} not connected to VM {}".format(
device['name'], vm.name))
p = device['vm'].run_service('qubes.USBDetach', passio_popen=True,
user='root')
(stdout, stderr) = p.communicate(
'{}\n'.format(device['device']))
if p.returncode != 0:
# TODO: sanitize and include stdout
raise QubesException('Device detach failed')
def usb_detach_all(qvmc, vm):
for dev in usb_list(qvmc).values():
connected_to = dev['connected-to']
if connected_to is not None and connected_to.qid == vm.qid:
usb_detach(qvmc, connected_to, dev)
####### QubesWatch ######
def only_in_first_list(l1, l2):
ret=[]
for i in l1:
if not i in l2:
ret.append(i)
return ret
class QubesWatch(object):
def __init__(self):
self._qdb = {}
self._qdb_events = {}
self.block_callback = None
self.meminfo_callback = None
self.domain_callback = None
libvirt.virEventRegisterDefaultImpl()
# open new libvirt connection because above
# virEventRegisterDefaultImpl is in practice effective only for new
# connections
self.libvirt_conn = libvirt.open(defaults['libvirt_uri'])
self.libvirt_conn.domainEventRegisterAny(
None,
libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE,
self._domain_list_changed, None)
self.libvirt_conn.domainEventRegisterAny(
None,
libvirt.VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED,
self._device_removed, None)
# TODO: device attach libvirt event
for vm in vmm.libvirt_conn.listAllDomains():
try:
if vm.isActive():
self._register_watches(vm)
except libvirt.libvirtError as e:
# this will happen if we loose a race with another tool,
# which can just remove the domain
if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
pass
else:
raise
# and for dom0
self._register_watches(None)
def _qdb_handler(self, watch, fd, events, domain_name):
try:
path = self._qdb[domain_name].read_watch()
except DisconnectedError:
libvirt.virEventRemoveHandle(watch)
del(self._qdb_events[domain_name])
self._qdb[domain_name].close()
del(self._qdb[domain_name])
return
if path.startswith('/qubes-block-devices'):
if self.block_callback is not None:
self.block_callback(domain_name)
def setup_block_watch(self, callback):
self.block_callback = callback
def setup_meminfo_watch(self, callback):
raise NotImplementedError
def setup_domain_watch(self, callback):
self.domain_callback = callback
def get_meminfo_key(self, xid):
return '/local/domain/%s/memory/meminfo' % xid
def _register_watches(self, libvirt_domain):
if libvirt_domain and libvirt_domain.ID() == 0:
# don't use libvirt object for dom0, to always have the same
# hardcoded "dom0" name
libvirt_domain = None
if libvirt_domain:
name = libvirt_domain.name()
if name in self._qdb:
return
if not libvirt_domain.isActive():
return
# open separate connection to Qubes DB:
# 1. to not confuse pull() with responses to real commands sent from
# other threads (like read, write etc) with watch events
# 2. to not think whether QubesDB is thread-safe (it isn't)
try:
self._qdb[name] = QubesDB(name)
except Error as e:
if e.args[0] != 2:
raise
libvirt.virEventAddTimeout(500, self._retry_register_watches,
libvirt_domain)
return
else:
name = "dom0"
if name in self._qdb:
return
self._qdb[name] = QubesDB(name)
try:
self._qdb[name].watch('/qubes-block-devices')
except Error as e:
if e.args[0] == 102: # Connection reset by peer
# QubesDB daemon not running - most likely we've connected to
# stale daemon which just exited; retry later
libvirt.virEventAddTimeout(500, self._retry_register_watches,
libvirt_domain)
return
self._qdb_events[name] = libvirt.virEventAddHandle(
self._qdb[name].watch_fd(),
libvirt.VIR_EVENT_HANDLE_READABLE,
self._qdb_handler, name)
def _retry_register_watches(self, timer, libvirt_domain):
libvirt.virEventRemoveTimeout(timer)
self._register_watches(libvirt_domain)
def _unregister_watches(self, libvirt_domain):
if libvirt_domain and libvirt_domain.ID() == 0:
name = "dom0"
else:
name = libvirt_domain.name()
if name in self._qdb_events:
libvirt.virEventRemoveHandle(self._qdb_events[name])
del(self._qdb_events[name])
if name in self._qdb:
self._qdb[name].close()
del(self._qdb[name])
def _domain_list_changed(self, conn, domain, event, reason, param):
# use VIR_DOMAIN_EVENT_RESUMED instead of VIR_DOMAIN_EVENT_STARTED to
# make sure that qubesdb daemon is already running
if event == libvirt.VIR_DOMAIN_EVENT_RESUMED:
self._register_watches(domain)
elif event == libvirt.VIR_DOMAIN_EVENT_STOPPED:
self._unregister_watches(domain)
else:
# ignore other events for now
return None
if self.domain_callback:
self.domain_callback(name=domain.name(), uuid=domain.UUID())
def _device_removed(self, conn, domain, device, param):
if self.block_callback is not None:
self.block_callback(domain.name())
def watch_loop(self):
while True:
libvirt.virEventRunDefaultImpl()
##### updates check #####
#
# XXX this whole section is a new global property
# TODO make event handlers
#
UPDATES_DOM0_DISABLE_FLAG='/var/lib/qubes/updates/disable-updates'
UPDATES_DEFAULT_VM_DISABLE_FLAG=\
'/var/lib/qubes/updates/vm-default-disable-updates'
def updates_vms_toggle(qvm_collection, value):
# Flag for new VMs
if value:
if os.path.exists(UPDATES_DEFAULT_VM_DISABLE_FLAG):
os.unlink(UPDATES_DEFAULT_VM_DISABLE_FLAG)
else:
open(UPDATES_DEFAULT_VM_DISABLE_FLAG, "w").close()
# Change for existing VMs
for vm in qvm_collection.values():
if vm.qid == 0:
continue
if value:
vm.services.pop('qubes-update-check', None)
if vm.is_running():
try:
vm.run("systemctl start qubes-update-check.timer",
user="root")
except:
pass
else:
vm.services['qubes-update-check'] = False
if vm.is_running():
try:
vm.run("systemctl stop qubes-update-check.timer",
user="root")
except:
pass
def updates_dom0_toggle(qvm_collection, value):
if value:
if os.path.exists(UPDATES_DOM0_DISABLE_FLAG):
os.unlink(UPDATES_DOM0_DISABLE_FLAG)
else:
open(UPDATES_DOM0_DISABLE_FLAG, "w").close()
def updates_dom0_status(qvm_collection):
return not os.path.exists(UPDATES_DOM0_DISABLE_FLAG)
def updates_vms_status(qvm_collection):
# default value:
status = not os.path.exists(UPDATES_DEFAULT_VM_DISABLE_FLAG)
# check if all the VMs uses the default value
for vm in qvm_collection.values():
if vm.qid == 0:
continue
if vm.services.get('qubes-update-check', True) != status:
# "mixed"
return None
return status
# vim:sw=4:et:

View File

@ -1,11 +0,0 @@
#!/usr/bin/python2
from __future__ import absolute_import
from qubes.storage.xen import XenStorage, XenPool
def apply(system_path, vm_files, defaults):
defaults['storage_class'] = XenStorage
defaults['pool_drivers'] = {'xen': XenPool}
defaults['pool_config'] = {'dir_path': '/var/lib/qubes/'}

View File

@ -1,24 +0,0 @@
OS ?= Linux
SYSCONFDIR ?= /etc
PYTHON_QUBESPATH = $(PYTHON_SITEPATH)/qubes
all:
python -m compileall .
python -O -m compileall .
install:
ifndef PYTHON_SITEPATH
$(error PYTHON_SITEPATH not defined)
endif
mkdir -p $(DESTDIR)$(PYTHON_QUBESPATH)/storage
cp __init__.py $(DESTDIR)$(PYTHON_QUBESPATH)/storage
cp __init__.py[co] $(DESTDIR)$(PYTHON_QUBESPATH)/storage
mkdir -p $(DESTDIR)$(SYSCONFDIR)/qubes
cp storage.conf $(DESTDIR)$(SYSCONFDIR)/qubes/
ifneq ($(BACKEND_VMM),)
if [ -r $(BACKEND_VMM).py ]; then \
cp $(BACKEND_VMM).py $(DESTDIR)$(PYTHON_QUBESPATH)/storage && \
cp $(BACKEND_VMM).py[co] $(DESTDIR)$(PYTHON_QUBESPATH)/storage; \
fi
endif

View File

@ -1,48 +0,0 @@
#!/usr/bin/python -O
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2014 Wojciech Porczyk <wojciech@porczyk.eu>
#
# 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 unittest
import qubes.qubesutils
class TestCaseFunctionsAndConstants(unittest.TestCase):
def check_output_int(self, cmd):
return int(subprocess.check_output(cmd).strip().split(None, 1)[0])
def test_00_BLKSIZE(self):
# this may fail on systems without st_blocks
self.assertEqual(qubes.qubesutils.BLKSIZE, self.check_output_int(['stat', '-c%B', '.']))
def test_01_get_size_one(self):
# this may fail on systems without st_blocks
self.assertEqual(qubes.qubesutils.get_disk_usage_one(os.stat('.')),
self.check_output_int(['stat', '-c%b', '.']) * qubes.qubesutils.BLKSIZE)
def test_02_get_size(self):
self.assertEqual(qubes.qubesutils.get_disk_usage('.'),
self.check_output_int(['du', '-s', '--block-size=1', '.']))
if __name__ == '__main__':
unittest.main()

2
dispvm/.gitignore vendored
View File

@ -1,2 +0,0 @@
qubes_restore
xenstore-watch

View File

@ -1,21 +0,0 @@
UNITDIR ?= /usr/lib/systemd/system
all:
true
clean:
true
install:
mkdir -p $(DESTDIR)/etc/xen/scripts
cp block.qubes $(DESTDIR)/etc/xen/scripts
mkdir -p $(DESTDIR)/usr/bin $(DESTDIR)/usr/lib/qubes
cp qubes-prepare-saved-domain.sh $(DESTDIR)/usr/lib/qubes
cp qubes-update-dispvm-savefile-with-progress.sh $(DESTDIR)/usr/lib/qubes
cp qfile-daemon-dvm $(DESTDIR)/usr/lib/qubes
mkdir -p $(DESTDIR)$(UNITDIR)
cp startup-dvm.sh $(DESTDIR)/usr/lib/qubes
cp qubes-setupdvm.service $(DESTDIR)$(UNITDIR)

View File

@ -1,61 +0,0 @@
#!/bin/bash
HOTPLUG_STORE="/var/run/xen-hotplug/${XENBUS_PATH//\//-}"
hd_arr[10]=a
hd_arr[11]=b
hd_arr[12]=c
hd_arr[13]=d
hd_arr[14]=e
hd_arr[15]=f
hexdigit()
{
if [ $1 -lt 10 ] ; then
RET=$1
else
RET=${hd_arr[$1]}
fi
}
hexnumber()
{
hexdigit $(($1/16))
ret2=$RET
hexdigit $(($1%16))
HEXNUMBER="$ret2"$RET
}
process()
{
if ! [ "x""$1" = "xfile" ] ; then
exec flock /var/run/qubes/hotplug-block /etc/xen/scripts/block $ORIG_ARGS
fi
while true ; do
dev=$(losetup -f --show $2)
if [ -n "$dev" ] ; then break ; fi
done
hexnumber ${dev:9:70}
xenstore-write "$XENBUS_PATH/node" "$dev" \
"$XENBUS_PATH/physical-device" "7:"$HEXNUMBER \
"$XENBUS_PATH/hotplug-status" connected
echo "$dev" > "$HOTPLUG_STORE-node"
echo "file" > "$HOTPLUG_STORE-type"
}
#exec 2>>/tmp/block.$$
#set -x
export PATH="/sbin:/bin:/usr/bin:/usr/sbin:$PATH"
XENBUS_PATH="${XENBUS_PATH:?}"
if ! [ "$1" = "add" ] || ! [ -f /var/run/qubes/fast-block-attach ] ; then
script=$(xenstore-read "$XENBUS_PATH/script")
exec flock /var/run/qubes/hotplug-block $script "$@"
fi
ORIG_ARGS="$@"
vars=$(xenstore-read "$XENBUS_PATH/type" "$XENBUS_PATH/params")
process $vars
exit 0

View File

@ -1,200 +0,0 @@
#!/usr/bin/python2
# coding=utf-8
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
# Copyright (C) 2013-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.
#
#
import os
import subprocess
import sys
import shutil
import time
from qubes.qubes import QubesVmCollection, QubesException
from qubes.qubes import QubesDispVmLabels
from qubes.notify import tray_notify, tray_notify_error, tray_notify_init
current_savefile = '/var/run/qubes/current-savefile'
current_savefile_vmdir = '/var/lib/qubes/dvmdata/vmdir'
class QfileDaemonDvm:
def __init__(self, name):
self.name = name
@staticmethod
def get_disp_templ():
vmdir = os.readlink(current_savefile_vmdir)
return vmdir.split('/')[-1]
def do_get_dvm(self):
tray_notify("Starting new DispVM...", "red")
qvm_collection = QubesVmCollection()
qvm_collection.lock_db_for_writing()
try:
tar_process = subprocess.Popen(
['bsdtar', '-C', current_savefile_vmdir,
'-xSUf', os.path.join(current_savefile_vmdir, 'saved-cows.tar')])
qvm_collection.load()
print >>sys.stderr, "time=%s, collection loaded" % (str(time.time()))
vm = qvm_collection.get_vm_by_name(self.name)
if vm is None:
sys.stderr.write('Domain ' + self.name + ' does not exist ?')
return None
label = vm.label
if len(sys.argv) > 4 and len(sys.argv[4]) > 0:
assert sys.argv[4] in QubesDispVmLabels.keys(), "Invalid label"
label = QubesDispVmLabels[sys.argv[4]]
disp_templ = self.get_disp_templ()
vm_disptempl = qvm_collection.get_vm_by_name(disp_templ)
if vm_disptempl is None:
sys.stderr.write('Domain ' + disp_templ + ' does not exist ?')
return None
dispvm = qvm_collection.add_new_vm('QubesDisposableVm',
disp_template=vm_disptempl,
label=label)
print >>sys.stderr, "time=%s, VM created" % (str(time.time()))
# By default inherit firewall rules from calling VM
disp_firewall_conf = '/var/run/qubes/%s-firewall.xml' % dispvm.name
dispvm.firewall_conf = disp_firewall_conf
if os.path.exists(vm.firewall_conf):
shutil.copy(vm.firewall_conf, disp_firewall_conf)
elif vm.qid == 0 and os.path.exists(vm_disptempl.firewall_conf):
# for DispVM called from dom0, copy use rules from DispVM template
shutil.copy(vm_disptempl.firewall_conf, disp_firewall_conf)
if len(sys.argv) > 5 and len(sys.argv[5]) > 0:
assert os.path.exists(sys.argv[5]), "Invalid firewall.conf location"
dispvm.firewall_conf = sys.argv[5]
if vm.qid != 0:
dispvm.uses_default_netvm = False
# netvm can be changed before restore,
# but cannot be enabled/disabled
if (dispvm.netvm is None) == (vm.dispvm_netvm is None):
dispvm.netvm = vm.dispvm_netvm
# Wait for tar to finish
if tar_process.wait() != 0:
sys.stderr.write('Failed to unpack saved-cows.tar')
return None
print >>sys.stderr, "time=%s, VM starting" % (str(time.time()))
try:
dispvm.start()
except (MemoryError, QubesException) as e:
tray_notify_error(str(e))
raise
if vm.qid != 0:
# if need to enable/disable netvm, do it while DispVM is alive
if (dispvm.netvm is None) != (vm.dispvm_netvm is None):
dispvm.netvm = vm.dispvm_netvm
print >>sys.stderr, "time=%s, VM started" % (str(time.time()))
qvm_collection.save()
finally:
qvm_collection.unlock_db()
# Reload firewall rules
print >>sys.stderr, "time=%s, reloading firewall" % (str(time.time()))
for vm in qvm_collection.values():
if vm.is_proxyvm() and vm.is_running():
vm.write_iptables_qubesdb_entry()
return dispvm
@staticmethod
def dvm_setup_ok():
dvmdata_dir = '/var/lib/qubes/dvmdata/'
if not os.path.isfile(current_savefile):
return False
if not os.path.isfile(dvmdata_dir+'default-savefile') or \
not os.path.isfile(dvmdata_dir+'savefile-root'):
return False
dvm_mtime = os.stat(current_savefile).st_mtime
root_mtime = os.stat(dvmdata_dir+'savefile-root').st_mtime
if dvm_mtime < root_mtime:
template_name = os.path.basename(
os.path.dirname(os.readlink(dvmdata_dir+'savefile-root')))
if subprocess.call(["xl", "domid", template_name],
stdout=open(os.devnull, "w")) == 0:
tray_notify("For optimum performance, you should not "
"start DispVM when its template is running.", "red")
return False
return True
def get_dvm(self):
if not self.dvm_setup_ok():
if os.system("/usr/lib/qubes/"
"qubes-update-dispvm-savefile-with-progress.sh"
" >/dev/null </dev/null") != 0:
tray_notify_error("DVM savefile creation failed")
return None
return self.do_get_dvm()
@staticmethod
def finish_disposable(name):
qvm_collection = QubesVmCollection()
qvm_collection.lock_db_for_writing()
qvm_collection.load()
vm = qvm_collection.get_vm_by_name(name)
if vm is None:
qvm_collection.unlock_db()
return False
try:
vm.force_shutdown()
except QubesException:
# VM already destroyed
pass
qvm_collection.pop(vm.qid)
qvm_collection.save()
qvm_collection.unlock_db()
def main():
exec_index = sys.argv[1]
if exec_index == "FINISH":
QfileDaemonDvm.finish_disposable(sys.argv[2])
return
src_vmname = sys.argv[2]
user = sys.argv[3]
# accessed directly by get_dvm()
# sys.argv[4] - override label
# sys.argv[5] - override firewall
print >>sys.stderr, "time=%s, qfile-daemon-dvm init" % (str(time.time()))
tray_notify_init()
print >>sys.stderr, "time=%s, creating DispVM" % (str(time.time()))
qfile = QfileDaemonDvm(src_vmname)
dispvm = qfile.get_dvm()
if dispvm is not None:
if exec_index == "LAUNCH":
print dispvm.name
return
print >>sys.stderr, "time=%s, starting VM process" % (str(time.time()))
subprocess.call(['/usr/lib/qubes/qrexec-client', '-d', dispvm.name,
user+':exec /usr/lib/qubes/qubes-rpc-multiplexer ' +
exec_index + " " + src_vmname])
QfileDaemonDvm.finish_disposable(dispvm.name)
main()

View File

@ -1,86 +0,0 @@
#!/bin/bash
set -o pipefail
get_encoded_script()
{
ENCODED_SCRIPT=`
if [ "$1" == "vm-default" ]; then
echo /usr/lib/qubes/dispvm-prerun.sh
else
cat "$1"
fi | base64 -w0` || exit 1
}
if [ $# != 2 -a $# != 3 ] ; then
echo "usage: $0 domainname savefile_to_be_created [preload script]" >&2
exit 1
fi
export PATH=$PATH:/sbin:/usr/sbin
if [ $# = 3 ] ; then
get_encoded_script $3
fi
VMDIR=/var/lib/qubes/appvms/$1
if ! [ -d $VMDIR ] ; then
echo "$VMDIR does not exist ?" >&2
exit 1
fi
if ! qvm-start $1 --dvm ; then
exit 1
fi
ID=`virsh -c xen:/// domid $1`
echo "Waiting for DVM $1 ..." >&2
if [ -n "$ENCODED_SCRIPT" ] ; then
qubesdb-write -d $1 /qubes-save-script "$ENCODED_SCRIPT"
fi
#set -x
qubesdb-write -d $1 /qubes-save-request 1
qubesdb-watch -d $1 /qubes-used-mem
qubesdb-read -d $1 /qubes-gateway | \
cut -d . -f 3 | tr -d "\n" > $VMDIR/netvm-id.txt
kill `cat /var/run/qubes/guid-running.$ID`
# FIXME: get connection URI from core scripts
virsh -c xen:/// detach-disk $1 xvdb
MEM=$(qubesdb-read -d $1 /qubes-used-mem | grep '^[0-9]\+$' | head -n 1)
echo "DVM boot complete, memory used=$MEM. Saving image..." >&2
QMEMMAN_STOP=/var/run/qubes/do-not-membalance
touch $QMEMMAN_STOP
virsh -c xen:/// setmem $1 $MEM
# Add some safety margin
virsh -c xen:/// setmaxmem $1 $[ $MEM + 1024 ]
# Stop qubesdb daemon now, so VM can restart it later
kill `cat /var/run/qubes/qubesdb.$1.pid`
sleep 1
touch $2
if ! virsh -c xen:/// save $1 $2; then
rm -f $QMEMMAN_STOP
qvm-kill $1
exit 1
fi
rm -f $QMEMMAN_STOP
# Do not allow smaller allocation than 400MB. If that small number comes from
# an error, it would prevent further savefile regeneration (because VM would
# not start with too little memory). Also 'maxmem' depends on 'memory', so
# 400MB is sane compromise.
if [ "$MEM" -lt 409600 ]; then
qvm-prefs -s $1 memory 400
else
qvm-prefs -s $1 memory $[ $MEM / 1024 ]
fi
ln -snf $VMDIR /var/lib/qubes/dvmdata/vmdir
cd $VMDIR
fstype=`df --output=fstype $VMDIR | tail -n 1`
if [ "$fstype" = "tmpfs" ]; then
# bsdtar doesn't work on tmpfs because FS_IOC_FIEMAP ioctl isn't supported
# there
tar -cSf saved-cows.tar volatile.img || exit 1
else
errors=`bsdtar -cSf saved-cows.tar volatile.img 2>&1`
if [ -n "$errors" ]; then
echo "Failed to create saved-cows.tar: $errors" >&2
rm -f saved-cows.tar
exit 1
fi
fi
echo "DVM savefile created successfully."

View File

@ -1,12 +0,0 @@
[Unit]
Description=Qubes DispVM startup setup
After=qubes-core.service
[Service]
Type=oneshot
ExecStart=/usr/lib/qubes/startup-dvm.sh
[Install]
WantedBy=multi-user.target
# Cover legacy init.d script
Alias=qubes_setupdvm.service

View File

@ -1,23 +0,0 @@
#!/bin/sh
line1="<b>Please wait (up to 120s) while the DispVM savefile is being updated.</b>"
line2="<i><small>This only happens when you have updated the template.</small></i>"
line3="<i><small>Next time will be much faster.</small></i>"
if [ -n "$KDE_FULL_SESSION" ]; then
br="<br/>"
else
br="
"
fi
notify-send --icon=/usr/share/qubes/icons/qubes.png --expire-time=120000 \
"Updating default DispVM savefile" "$line1$br$line2$br$line3"
ret=0
rm -f /var/run/qubes/qvm-create-default-dvm.stdout
if ! qvm-create-default-dvm --used-template --default-script >/var/run/qubes/qvm-create-default-dvm.stdout </dev/null ; then
ret=1
fi
exit $ret

View File

@ -1,22 +0,0 @@
#!/bin/sh
# Setup DispVM things at Qubes system startup
printf "\x00\x00\x00\x00" > /var/run/qubes/dispVM.seq
chown root:qubes /var/run/qubes/dispVM.seq
chmod 660 /var/run/qubes/dispVM.seq
DEFAULT=/var/lib/qubes/dvmdata/default-savefile
# setup DispVM files only when they exists
if [ -r $DEFAULT ]; then
if [ -f /var/lib/qubes/dvmdata/dont-use-shm ] ; then
ln -s $DEFAULT /var/run/qubes/current-savefile
else
mkdir -m 770 /dev/shm/qubes
chown root.qubes /dev/shm/qubes
cp -a $(readlink $DEFAULT) /dev/shm/qubes/current-savefile
chown root.qubes /dev/shm/qubes/current-savefile
chmod 660 /dev/shm/qubes/current-savefile
ln -s /dev/shm/qubes/current-savefile /var/run/qubes/current-savefile
fi
fi

View File

@ -7,7 +7,6 @@ install:
cp block-snapshot $(DESTDIR)/etc/xen/scripts
ln -s block-snapshot $(DESTDIR)/etc/xen/scripts/block-origin
install -d $(DESTDIR)/etc/xdg/autostart
install -m 0644 qubes-guid.desktop $(DESTDIR)/etc/xdg/autostart/
install -m 0644 qrexec-policy-agent.desktop $(DESTDIR)/etc/xdg/autostart/
install -m 0644 -D tmpfiles-qubes.conf $(DESTDIR)/usr/lib/tmpfiles.d/qubes.conf
install -d $(DESTDIR)/etc/dbus-1/system.d

View File

@ -1,7 +0,0 @@
[Desktop Entry]
Name=Qubes Guid
Comment=Starts Dom0 GUI daemon for Qubes VMs
Icon=qubes
Exec=qvm-run --all true
Terminal=false
Type=Application

View File

@ -1,161 +0,0 @@
#!/usr/bin/python
# -*- encoding: utf8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2012 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.
#
#
from qubes.qubes import QubesVmCollection
from qubes.qubes import QubesHost
from qubes.qubes import system_path
from optparse import OptionParser
import subprocess
import os
import sys
from qubes.qubes import vmm
def handle_vm(vms, label, new_value = None):
functions = { # label: [ getter, setter ],
'default-netvm': [ 'get_default_netvm', 'set_default_netvm' ],
'default-fw-netvm': [ 'get_default_fw_netvm', 'set_default_fw_netvm' ],
'default-template': [ 'get_default_template', 'set_default_template' ],
'clockvm': [ 'get_clockvm_vm', 'set_clockvm_vm' ],
'updatevm': [ 'get_updatevm_vm', 'set_updatevm_vm' ],
}
assert label in functions.keys()
if new_value:
if new_value == "none":
try:
vms.__getattribute__(functions[label][1])(None)
except Exception as e:
print >> sys.stderr, "ERROR: {0}".format(str(e))
exit(1)
else:
vm = vms.get_vm_by_name (new_value)
if vm is None:
print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(new_value)
exit(1)
try:
vms.__getattribute__(functions[label][1])(vm)
except Exception as e:
print >> sys.stderr, "ERROR: {0}".format(str(e))
exit(1)
else:
vm = vms.__getattribute__(functions[label][0])()
if vm is not None:
return vm.name
else:
return ""
def handle_kernel(vms, label, new_value = None):
if new_value is not None:
if not os.path.exists(os.path.join(system_path["qubes_kernels_base_dir"], new_value)):
print >> sys.stderr, "Kernel version {0} not installed.".format(new_value)
print >> sys.stderr, "Available versions:"
for k in os.listdir(system_path["qubes_kernels_base_dir"]):
print >> sys.stderr, " -", k
exit(1)
vms.set_default_kernel(new_value)
else:
return vms.get_default_kernel()
preferences = {
"default-netvm": handle_vm,
"default-fw-netvm": handle_vm,
"default-template": handle_vm,
"clockvm": handle_vm,
"updatevm": handle_vm,
"default-kernel": handle_kernel,
}
def do_list(vms):
label_width = 18
fmt="{{0:<{0}}}: {{1}}".format(label_width)
for pref in sorted(preferences.items()):
print fmt.format (pref[0], pref[1](vms, pref[0]))
def main():
usage = "usage: %prog [-l]\n"\
"usage: %prog [-g] <property>\n"\
"usage: %prog [-s] <property> <new-value>\n"\
"List/set various global properties."
parser = OptionParser (usage)
parser.add_option ("-l", "--list", action="store_true", dest="do_list", default=False)
parser.add_option ("-s", "--set", action="store_true", dest="do_set", default=False)
parser.add_option ("-g", "--get", action="store_true", dest="do_get", default=False)
(options, args) = parser.parse_args ()
if options.do_list + options.do_set + options.do_get > 1:
print >> sys.stderr, "You can provide only one action at once!"
exit (1)
# Select action based on args count:
if not options.do_list and not options.do_get and not options.do_set:
if (len (args) < 1):
options.do_list = True
elif (len (args) == 1):
options.do_get = True
else:
options.do_set = True
vmm.offline_mode = True
if options.do_set:
qvm_collection = QubesVmCollection()
qvm_collection.lock_db_for_writing()
qvm_collection.load()
else:
qvm_collection = QubesVmCollection()
qvm_collection.lock_db_for_reading()
qvm_collection.load()
qvm_collection.unlock_db()
if options.do_set:
if len (args) < 2 or args[0] not in preferences.keys():
print >> sys.stderr, "You must specify the property and the new value you wish to set..."
print >> sys.stderr, "Available properties:"
for p in sorted(preferences.keys()):
print >> sys.stderr, "--> '{0}'".format(p)
exit (1)
pref = args[0]
new_value = args[1]
preferences[pref](qvm_collection, pref, new_value)
qvm_collection.save()
qvm_collection.unlock_db()
elif options.do_get:
if len (args) < 1 or args[0] not in preferences.keys():
print >> sys.stderr, "You must specify the property you wish to get..."
print >> sys.stderr, "Available properties:"
for p in sorted(preferences.keys()):
print >> sys.stderr, "--> '{0}'".format(p)
exit (1)
pref = args[0]
print preferences[pref](qvm_collection, pref)
else:
# do_list
do_list(qvm_collection)
main()

View File

@ -1,85 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2014 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.
#
#
from optparse import OptionParser
import optparse
import os
import sys
from qubes.qubes import QubesVmCollection
from qubes.qubesutils import updates_vms_toggle,updates_dom0_toggle,\
updates_dom0_status,updates_vms_status
from qubes.qubes import vmm
def main():
usage = "%prog enable|disable|status\n"\
" Enable or disable globally checking for updates (both dom0 and VM)"
parser = OptionParser (usage)
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:
parser.error("You must provide an action")
action = args[0]
if action not in ['enable', 'disable', 'status']:
parser.error("Invalid action")
if options.offline_mode:
vmm.offline_mode = True
qvm_collection = QubesVmCollection()
if action == 'status':
qvm_collection.lock_db_for_reading()
else:
qvm_collection.lock_db_for_writing()
qvm_collection.load()
if action == 'enable':
updates_dom0_toggle(qvm_collection, True)
updates_vms_toggle(qvm_collection, True)
elif action == 'disable':
updates_dom0_toggle(qvm_collection, False)
updates_vms_toggle(qvm_collection, False)
else:
if updates_dom0_status(qvm_collection):
print "dom0: enabled"
else:
print "dom0: disabled"
status_vms = updates_vms_status(qvm_collection)
if status_vms is None:
print "vms: mixed"
elif status_vms:
print "vms: enabled"
else:
print "vms: disabled"
if action != 'status':
qvm_collection.save()
qvm_collection.unlock_db()
if __name__ == "__main__":
main()

View File

@ -1,86 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# 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.
#
#
from qubes.qubes import QubesVmCollection
from qubes.qubes import QubesException
from optparse import OptionParser;
import sys
import os
def main():
usage = "usage: %prog [options] <appvm-name> <vm-template-name>\n\n"\
"Adds an already installed appvm to the Qubes DB\n"\
"WARNING: Noramlly you would not need this command,\n"\
"and you would use qvm-create instead!"
parser = OptionParser (usage)
parser.add_option ("-p", "--path", dest="dir_path",
help="Specify path to the template directory")
parser.add_option ("-c", "--conf", dest="conf_file",
help="Specify the Xen VM .conf file to use\
(relative to the template dir path)")
parser.add_option ("--force-root", action="store_true", dest="force_root", default=False,
help="Force to run, even with root privileges")
(options, args) = parser.parse_args ()
if (len (args) != 2):
parser.error ("You must specify at least the AppVM and TemplateVM names!")
vmname = args[0]
templatename = args[1]
if hasattr(os, "geteuid") and 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_writing()
qvm_collection.load()
if qvm_collection.get_vm_by_name(vmname) is not None:
print >> sys.stderr, "ERROR: A VM with the name '{0}' already exists in the system.".format(vmname)
exit(1)
template = qvm_collection.get_vm_by_name(templatename)
if template is None:
print >> sys.stderr, "ERROR: A Template VM with the name '{0}' does not exist in the system.".format(templatename)
exit(1)
vm = qvm_collection.add_new_vm("QubesAppVm", name=vmname, template=template,
conf_file=options.conf_file,
dir_path=options.dir_path)
try:
vm.verify_files()
except QubesException as err:
print >> sys.stderr, "ERROR: {0}".format(err)
qvm_collection.pop(vm.qid)
exit (1)
qvm_collection.save()
qvm_collection.unlock_db()
main()

View File

@ -1,83 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# 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.
#
#
from qubes.qubes import QubesVmCollection,vmm
from qubes.qubes import QubesException
from optparse import OptionParser;
import sys
import os
def main():
usage = "usage: %prog [options] <vm-template-name>\n"\
"Adds an already installed template to the Qubes DB"
parser = OptionParser (usage)
parser.add_option ("-p", "--path", dest="dir_path",
help="Specify path to the template directory")
parser.add_option ("-c", "--conf", dest="conf_file",
help="Specify the Xen VM .conf file to use\
(relative to the template dir path)")
parser.add_option ("--rpm", action="store_true", dest="installed_by_rpm",
help="Template files have been installed by RPM", default=False)
parser.add_option ("--force-root", action="store_true", dest="force_root", default=False,
help="Force to run, even with root privileges")
(options, args) = parser.parse_args ()
if (len (args) != 1):
parser.error ("You must specify at least the TemplateVM name!")
vmname = args[0]
if hasattr(os, "geteuid") and os.geteuid() == 0:
if not options.force_root and not options.installed_by_rpm:
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)
vmm.offline_mode = True
qvm_collection = QubesVmCollection()
qvm_collection.lock_db_for_writing()
qvm_collection.load()
if qvm_collection.get_vm_by_name(vmname) is not None:
print >> sys.stderr, "ERROR: A VM with the name '{0}' already exists in the system.".format(vmname)
exit(1)
vm = qvm_collection.add_new_vm("QubesTemplateVm", name=vmname,
conf_file=options.conf_file,
dir_path=options.dir_path,
installed_by_rpm=options.installed_by_rpm)
try:
vm.verify_files()
except QubesException as err:
print >> sys.stderr, "ERROR: {0}".format(err)
qvm_collection.pop(vm.qid)
exit (1)
qvm_collection.save()
qvm_collection.unlock_db()
main()

View File

@ -1,218 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# 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.
#
#
from qubes.qubes import QubesVmCollection
from qubes.qubes import QubesException
from qubes.backup import backup_prepare, backup_do
from qubes.qubesutils import size_to_human
from optparse import OptionParser
import qubes.backup
import os
import sys
import getpass
from locale import getpreferredencoding
def print_progress(progress):
print >> sys.stderr, "\r-> Backing up files: {0}%...".format (progress),
def main():
usage = "usage: %prog [options] <backup-dir-path> [vms-to-be-included ...]"
parser = OptionParser (usage)
parser.add_option ("-x", "--exclude", action="append",
dest="exclude_list", default=[],
help="Exclude the specified VM from the backup (may be "
"repeated)")
parser.add_option ("--force-root", action="store_true", dest="force_root", default=False,
help="Force to run with root privileges")
parser.add_option ("-d", "--dest-vm", action="store", dest="appvm",
help="Specify the destination VM to which the backup "
"will be sent (implies -e)")
parser.add_option ("-e", "--encrypt", action="store_true", dest="encrypt", default=False,
help="Encrypt the backup")
parser.add_option ("--no-encrypt", action="store_true",
dest="no_encrypt", default=False,
help="Skip encryption even if sending the backup to a "
"VM")
parser.add_option ("-p", "--passphrase-file", action="store",
dest="pass_file", default=None,
help="Read passphrase from a file, or use '-' to read "
"from stdin")
parser.add_option ("-E", "--enc-algo", action="store",
dest="crypto_algorithm", default=None,
help="Specify a non-default encryption algorithm. For a "
"list of supported algorithms, execute 'openssl "
"list-cipher-algorithms' (implies -e)")
parser.add_option ("-H", "--hmac-algo", action="store",
dest="hmac_algorithm", default=None,
help="Specify a non-default HMAC algorithm. For a list "
"of supported algorithms, execute 'openssl "
"list-message-digest-algorithms'")
parser.add_option ("-z", "--compress", action="store_true", dest="compress", default=False,
help="Compress the backup")
parser.add_option ("-Z", "--compress-filter", action="store",
dest="compress_filter", default=False,
help="Specify a non-default compression filter program "
"(default: gzip)")
parser.add_option("--tmpdir", action="store", dest="tmpdir", default=None,
help="Specify a temporary directory (if you have at least "
"1GB free RAM in dom0, use of /tmp is advised) ("
"default: /var/tmp)")
parser.add_option ("--debug", action="store_true", dest="debug",
default=False, help="Enable (a lot of) debug output")
(options, args) = parser.parse_args ()
if (len (args) < 1):
print >> sys.stderr, "You must specify the target backup directory "\
" (e.g. /mnt/backup)."
print >> sys.stderr, "qvm-backup will create a subdirectory there for "\
" each individual backup."
exit (0)
base_backup_dir = args[0]
if hasattr(os, "geteuid") and os.geteuid() == 0:
if not options.force_root:
print >> sys.stderr, "*** Running this tool as root is strongly "\
"discouraged. This will lead to permissions "\
"problems."
print >> sys.stderr, "Retry as an unprivileged user, or use "\
"--force-root to continue anyway."
exit(1)
# Only for locking
qvm_collection = QubesVmCollection()
qvm_collection.lock_db_for_reading()
qvm_collection.load()
vms = None
if (len (args) > 1):
vms = [qvm_collection.get_vm_by_name(vmname) for vmname in args[1:]]
if options.appvm:
options.exclude_list.append(options.appvm)
if options.appvm or options.crypto_algorithm:
options.encrypt = True
if options.no_encrypt:
options.encrypt = False
if options.debug:
qubes.backup.BACKUP_DEBUG = True
files_to_backup = None
try:
files_to_backup = backup_prepare(
vms_list=vms,
exclude_list=options.exclude_list,
hide_vm_names=options.encrypt)
except QubesException as e:
print >>sys.stderr, "ERROR: %s" % str(e)
exit(1)
total_backup_sz = reduce(lambda size, file: size+file["size"],
files_to_backup, 0)
if not options.appvm:
appvm = None
if os.path.isdir(base_backup_dir):
stat = os.statvfs(base_backup_dir)
else:
stat = os.statvfs(os.path.dirname(base_backup_dir))
backup_fs_free_sz = stat.f_bsize * stat.f_bavail
print
if (total_backup_sz > backup_fs_free_sz):
print >>sys.stderr, "ERROR: Not enough space available on the "\
"backup filesystem!"
exit(1)
print "-> Available space: {0}".format(size_to_human(backup_fs_free_sz))
else:
appvm = qvm_collection.get_vm_by_name(options.appvm)
if appvm is None:
print >>sys.stderr, "ERROR: VM {0} does not exist!".format(options.appvm)
exit(1)
stat = os.statvfs('/var/tmp')
backup_fs_free_sz = stat.f_bsize * stat.f_bavail
print
if (backup_fs_free_sz < 1000000000):
print >>sys.stderr, "ERROR: Not enough space available " \
"on the local filesystem (1GB required for temporary files)!"
exit(1)
if not appvm.is_running():
appvm.start(verbose=True)
if options.appvm:
print >>sys.stderr, ("NOTE: VM {} will be excluded because it is "
"the backup destination.").format(options.appvm)
options.exclude_list.append(options.appvm)
if not options.encrypt:
print >>sys.stderr, "WARNING: The backup will NOT be encrypted!"
if options.pass_file is not None:
f = open(options.pass_file) if options.pass_file != "-" else sys.stdin
passphrase = f.readline().rstrip()
if f is not sys.stdin:
f.close()
else:
if raw_input("Do you want to proceed? [y/N] ").upper() != "Y":
exit(0)
s = ("Please enter the passphrase that will be used to {}verify "
"the backup: ").format('encrypt and ' if options.encrypt else '')
passphrase = getpass.getpass(s)
if getpass.getpass("Enter again for verification: ") != passphrase:
print >>sys.stderr, "ERROR: Passphrase mismatch!"
exit(1)
encoding = sys.stdin.encoding or getpreferredencoding()
passphrase = passphrase.decode(encoding)
kwargs = {}
if options.hmac_algorithm:
kwargs['hmac_algorithm'] = options.hmac_algorithm
if options.crypto_algorithm:
kwargs['crypto_algorithm'] = options.crypto_algorithm
if options.tmpdir:
kwargs['tmpdir'] = options.tmpdir
try:
backup_do(base_backup_dir, files_to_backup, passphrase,
progress_callback=print_progress,
encrypted=options.encrypt,
compressed=options.compress_filter or options.compress,
appvm=appvm, **kwargs)
except QubesException as e:
print >>sys.stderr, "ERROR: %s" % str(e)
exit(1)
print
print "-> Backup completed."
qvm_collection.unlock_db()
main()

View File

@ -1,313 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# 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.
#
#
from multiprocessing import Event
from qubes.qubes import QubesVmCollection
from qubes.qubes import QubesException
from qubes.backup import backup_restore_header
from qubes.backup import backup_restore_prepare
from qubes.backup import backup_restore_print_summary
from qubes.backup import backup_restore_do
import qubes.backup
import sys
from optparse import OptionParser
from locale import getpreferredencoding
import os
import sys
import getpass
def main():
usage = "usage: %prog [options] <backup-dir> [vms-to-be-restored ...]"
parser = OptionParser (usage)
parser.add_option ("--verify-only", action="store_true",
dest="verify_only", default=False,
help="Verify backup integrity without restoring any "
"data")
parser.add_option ("--skip-broken", action="store_true", dest="skip_broken", default=False,
help="Do not restore VMs that have missing TemplateVMs "
"or NetVMs")
parser.add_option ("--ignore-missing", action="store_true", dest="ignore_missing", default=False,
help="Restore VMs even if their associated TemplateVMs "
"and NetVMs are missing")
parser.add_option ("--skip-conflicting", action="store_true", dest="skip_conflicting", default=False,
help="Do not restore VMs that are already present on "
"the host")
parser.add_option ("--rename-conflicting", action="store_true",
dest="rename_conflicting", default=False,
help="Restore VMs that are already present on the host "
"under different names")
parser.add_option ("--force-root", action="store_true", dest="force_root", default=False,
help="Force to run with root privileges")
parser.add_option ("--replace-template", action="append", dest="replace_template", default=[],
help="Restore VMs using another TemplateVM; syntax: "
"old-template-name:new-template-name (may be "
"repeated)")
parser.add_option ("-x", "--exclude", action="append", dest="exclude", default=[],
help="Skip restore of specified VM (may be repeated)")
parser.add_option ("--skip-dom0-home", action="store_false", dest="dom0_home", default=True,
help="Do not restore dom0 user home directory")
parser.add_option ("--ignore-username-mismatch", action="store_true", dest="ignore_username_mismatch", default=False,
help="Ignore dom0 username mismatch when restoring home "
"directory")
parser.add_option ("-d", "--dest-vm", action="store", dest="appvm",
help="Specify VM containing the backup to be restored")
parser.add_option ("-e", "--encrypted", action="store_true", dest="decrypt", default=False,
help="The backup is encrypted")
parser.add_option ("-p", "--passphrase-file", action="store",
dest="pass_file", default=None,
help="Read passphrase from file, or use '-' to read from stdin")
parser.add_option ("-z", "--compressed", action="store_true", dest="compressed", default=False,
help="The backup is compressed")
parser.add_option ("--debug", action="store_true", dest="debug",
default=False, help="Enable (a lot of) debug output")
(options, args) = parser.parse_args ()
if (len (args) < 1):
print >> sys.stderr, "You must specify the backup directory "\
"(e.g. /mnt/backup/qubes-2010-12-01-235959)"
exit (0)
backup_dir = args[0]
vmlist = args[1:]
#if not os.path.exists (backup_dir):
# print >> sys.stderr, "The backup directory doesn't exist!"
# exit(1)
host_collection = QubesVmCollection()
host_collection.lock_db_for_writing()
host_collection.load()
restore_options = {}
if options.ignore_missing:
restore_options['use-default-template'] = True
restore_options['use-default-netvm'] = True
if options.replace_template:
restore_options['replace-template'] = options.replace_template
if options.rename_conflicting:
restore_options['rename-conflicting'] = True
if not options.dom0_home:
restore_options['dom0-home'] = False
if options.ignore_username_mismatch:
restore_options['ignore-username-mismatch'] = True
if options.exclude:
restore_options['exclude'] = options.exclude
if options.verify_only:
restore_options['verify-only'] = True
if options.debug:
qubes.backup.BACKUP_DEBUG = True
appvm = None
if options.appvm is not None:
appvm = host_collection.get_vm_by_name(options.appvm)
if appvm is None:
print >>sys.stderr, "ERROR: VM {0} does not exist".format(options.appvm)
exit(1)
if options.pass_file is not None:
f = open(options.pass_file) if options.pass_file != "-" else sys.stdin
passphrase = f.readline().rstrip()
if f is not sys.stdin:
f.close()
else:
passphrase = getpass.getpass("Please enter the passphrase to verify "
"and (if encrypted) decrypt the backup: ")
encoding = sys.stdin.encoding or getpreferredencoding()
passphrase = passphrase.decode(encoding)
print >> sys.stderr, "Checking backup content..."
error_detected = Event()
def error_callback(message):
error_detected.set()
print >> sys.stderr, message
restore_info = None
try:
restore_info = backup_restore_prepare(
backup_dir,
passphrase=passphrase,
options=restore_options,
host_collection=host_collection,
encrypted=options.decrypt,
compressed=options.compressed,
appvm=appvm,
error_callback=error_callback)
except QubesException as e:
print >> sys.stderr, "ERROR: %s" % str(e)
exit(1)
if len(vmlist) > 0:
for vm in restore_info.keys():
if vm.startswith('$'):
continue
if not vm in vmlist:
restore_info.pop(vm)
backup_restore_print_summary(restore_info)
there_are_conflicting_vms = False
there_are_missing_templates = False
there_are_missing_netvms = False
dom0_username_mismatch = False
for vm_info in restore_info.values():
if 'excluded' in vm_info and vm_info['excluded']:
continue
if 'missing-template' in vm_info.keys():
there_are_missing_templates = True
if 'missing-netvm' in vm_info.keys():
there_are_missing_netvms = True
if 'already-exists' in vm_info.keys():
there_are_conflicting_vms = True
if 'username-mismatch' in vm_info.keys():
dom0_username_mismatch = True
print
if hasattr(os, "geteuid") and os.geteuid() == 0:
print >> sys.stderr, "*** Running this tool as root is strongly "\
"discouraged. This will lead to permissions "\
"problems."
if options.force_root:
print >> sys.stderr, "Continuing as commanded. You have been "\
"warned."
else:
print >> sys.stderr, "Retry as an unprivileged user, or use "\
"--force-root to continue anyway."
exit(1)
if there_are_conflicting_vms:
print >> sys.stderr, "*** There are VMs with conflicting names on the "\
"host! ***"
if options.skip_conflicting:
print >> sys.stderr, "Those VMs will not be restored. The host "\
"VMs will NOT be overwritten."
else:
print >> sys.stderr, "Remove VMs with conflicting names from the "\
"host before proceeding."
print >> sys.stderr, "Or use --skip-conflicting to restore only "\
"those VMs that do not exist on the host."
print >> sys.stderr, "Or use --rename-conflicting to restore " \
"those VMs under modified names (with "\
"numbers at the end)."
exit (1)
print "The above VMs will be copied and added to your system."
print "Exisiting VMs will NOT be removed."
if there_are_missing_templates:
print >> sys.stderr, "*** One or more TemplateVMs are missing on the"\
"host! ***"
if not (options.skip_broken or options.ignore_missing):
print >> sys.stderr, "Install them before proceeding with the "\
"restore."
print >> sys.stderr, "Or pass: --skip-broken or --ignore-missing."
exit (1)
elif options.skip_broken:
print >> sys.stderr, "Skipping broken entries: VMs that depend on "\
"missing TemplateVMs will NOT be restored."
elif options.ignore_missing:
print >> sys.stderr, "Ignoring missing entries: VMs that depend "\
"on missing TemplateVMs will NOT be restored."
else:
print >> sys.stderr, "INTERNAL ERROR! Please report this to the "\
"Qubes OS team!"
exit (1)
if there_are_missing_netvms:
print >> sys.stderr, "*** One or more NetVMs are missing on the "\
"host! ***"
if not (options.skip_broken or options.ignore_missing):
print >> sys.stderr, "Install them before proceeding with the "\
"restore."
print >> sys.stderr, "Or pass: --skip-broken or --ignore-missing."
exit (1)
elif options.skip_broken:
print >> sys.stderr, "Skipping broken entries: VMs that depend on "\
"missing NetVMs will NOT be restored."
elif options.ignore_missing:
print >> sys.stderr, "Ignoring missing entries: VMs that depend "\
"on missing NetVMs will NOT be restored."
else:
print >> sys.stderr, "INTERNAL ERROR! Please report this to the "\
"Qubes OS team!"
exit (1)
if 'dom0' in restore_info.keys() and options.dom0_home:
if dom0_username_mismatch:
print >> sys.stderr, "*** Dom0 username mismatch! This can break "\
"some settings! ***"
if not options.ignore_username_mismatch:
print >> sys.stderr, "Skip restoring the dom0 home directory "\
"(--skip-dom0-home), or pass "\
"--ignore-username-mismatch to continue "\
"anyway."
exit(1)
else:
print >> sys.stderr, "Continuing as directed."
print >> sys.stderr, "NOTE: Before restoring the dom0 home directory, "\
"a new directory named "\
"'home-pre-restore-<current-time>' will be "\
"created inside the dom0 home directory. If any "\
"restored files conflict with existing files, "\
"the existing files will be moved to this new "\
"directory."
if options.pass_file is None:
if raw_input("Do you want to proceed? [y/N] ").upper() != "Y":
exit(0)
try:
backup_restore_do(restore_info,
host_collection=host_collection,
error_callback=error_callback)
except QubesException as e:
print >> sys.stderr, "ERROR: %s" % str(e)
host_collection.unlock_db()
if error_detected.is_set():
print "-> Completed with errors!"
exit(1)
else:
print "-> Done."
main()

View File

@ -1,152 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2010 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.
#
#
from qubes.qubes import QubesVmCollection, QubesException
from qubes.qubesutils import block_list,block_attach,block_detach,block_detach_all,block_check_attached
from qubes.qubesutils import kbytes_to_kmg, bytes_to_kmg
from optparse import OptionParser
import subprocess
import sys
import os
def main():
usage = "usage: %prog -l [options]\n"\
"usage: %prog -a [options] <vm-name> <device-vm-name>:<device>\n"\
"usage: %prog -A [options] <vm-name> <file-vm-name>:<file>\n"\
"usage: %prog -d [options] <device-vm-name>:<device>\n"\
"usage: %prog -d [options] <vm-name>\n"\
"List/set VM block devices."
parser = OptionParser (usage)
parser.add_option ("-l", "--list", action="store_true", dest="do_list", default=False)
parser.add_option ("-A", "--attach-file", action="store_true", dest="do_file_attach", default=False,
help="Attach specified file instead of physical device")
parser.add_option ("-a", "--attach", action="store_true", dest="do_attach", default=False)
parser.add_option ("-d", "--detach", action="store_true", dest="do_detach", default=False)
parser.add_option ("-f", "--frontend", dest="frontend",
help="Specify device name at destination VM [default: xvdi]")
parser.add_option ("--ro", dest="ro", action="store_true", default=False,
help="Force read-only mode")
parser.add_option ("--no-auto-detach", dest="auto_detach", action="store_false", default=True,
help="Fail when device already connected to other VM")
parser.add_option ("--show-system-disks", dest="system_disks", action="store_true", default=False,
help="List also system disks")
parser.add_option ("--force-root", action="store_true", dest="force_root", default=False,
help="Force to run, even with root privileges")
(options, args) = parser.parse_args ()
if hasattr(os, "geteuid") and 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)
if options.do_file_attach:
options.do_attach = True
if options.do_list + options.do_attach + options.do_detach > 1:
print >> sys.stderr, "Only one of -l -a/-A -d is allowed!"
exit (1)
qvm_collection = QubesVmCollection()
qvm_collection.lock_db_for_reading()
qvm_collection.load()
qvm_collection.unlock_db()
if options.do_attach:
if len(args) != 2:
parser.error ("You must provide vm name and device!")
vm = qvm_collection.get_vm_by_name(args[0])
if vm is None:
parser.error ("Invalid VM name: %s" % args[0])
# FIXME: here we assume that device is always in form "domain:dev", which can be changed in the future
if args[1].find(":") < 0:
parser.error ("Invalid device syntax (missing VM name): %s" % args[1])
if options.do_file_attach:
dev = {}
(dev['vm'], dev['device']) = args[1].split(":")
dev['desc'] = dev['device']
dev['mode'] = 'w'
else:
dev_list = block_list(qvm_collection)
if not args[1] in dev_list.keys():
parser.error ("Invalid device name: %s" % args[1])
dev = dev_list[args[1]]
kwargs = {}
if options.frontend:
kwargs['frontend'] = options.frontend
if options.ro:
kwargs['mode'] = "r"
else:
kwargs['mode'] = dev['mode']
kwargs['auto_detach'] = options.auto_detach
try:
block_attach(qvm_collection, vm, dev, **kwargs)
except QubesException as e:
print >> sys.stderr, "ERROR: %s" % str(e)
sys.exit(1)
elif options.do_detach:
if (len (args) < 1):
parser.error ("You must provide device or vm name!")
if len(args) > 1:
parser.error ("Too many parameters")
# Check if provided name is VM
vm = qvm_collection.get_vm_by_name(args[0])
if vm is not None:
kwargs = {}
if options.frontend:
kwargs['frontend'] = options.frontend
block_detach(vm, **kwargs)
else:
block_detach_all(vm)
else:
# Maybe device?
dev_list = block_list(qvm_collection)
if not args[0] in dev_list.keys():
parser.error ("Invalid VM or device name: %s" % args[0])
dev = dev_list[args[0]]
attached_to = block_check_attached(qvm_collection, dev)
if attached_to is None:
print >> sys.stderr, "WARNING: Device not connected to any VM"
exit(0)
block_detach(attached_to['vm'], attached_to['frontend'])
else:
# do_list
if len(args) > 0:
parser.error ("Too many parameters")
kwargs = {}
kwargs['qvmc'] = qvm_collection
kwargs['system_disks'] = options.system_disks
for dev in block_list(**kwargs).values():
attached_to = block_check_attached(qvm_collection, dev)
attached_to_str = ""
if attached_to:
attached_to_str = " (attached to '%s' as '%s')" % (
attached_to['vm'].name, attached_to['frontend'])
size_str = bytes_to_kmg(dev['size'])
print "%s\t%s %s%s" % (dev['name'], dev['desc'], size_str, attached_to_str)
exit (0)
main()

View File

@ -1,81 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2011 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.
#
#
from qubes.qubes import QubesVmCollection,QubesException
from optparse import OptionParser
import sys
import time
def main():
usage = """usage: %prog [options] <vm-name>\n
Specify no state options to check if VM exists"""
parser = OptionParser (usage)
parser.add_option ("-q", "--quiet", action="store_false", dest="verbose", default=True)
parser.add_option ("--running", action="store_true", dest="running", default=False,
help="Determine if VM is running")
parser.add_option ("--paused", action="store_true", dest="paused", default=False,
help="Determine if VM is paused")
parser.add_option ("--template", action="store_true", dest="template", default=False,
help="Determine if VM is a template")
(options, args) = parser.parse_args ()
if (len (args) != 1):
parser.error ("You must specify VM name!")
qvm_collection = QubesVmCollection()
qvm_collection.lock_db_for_reading()
qvm_collection.load()
qvm_collection.unlock_db()
vmname = args[0]
vm = qvm_collection.get_vm_by_name(vmname)
if vm is None:
if options.verbose:
print >> sys.stderr, "A VM with the name '{0}' does not exist in the system!".format(vmname)
exit(1)
elif options.running:
vm_state = not vm.is_running()
if options.verbose:
print >> sys.stderr, "A VM with the name {0} is {1}running.".format(vmname, "not " * vm_state)
exit(vm_state)
elif options.paused:
vm_state = not vm.is_paused()
if options.verbose:
print >> sys.stderr, "A VM with the name {0} is {1}paused.".format(vmname, "not " * vm_state)
exit(vm_state)
elif options.template:
vm_state = not vm.is_template()
if options.verbose:
print >> sys.stderr, "A VM with the name {0} is {1}a template.".format(vmname, "not " * vm_state)
exit(vm_state)
else:
if options.verbose:
print >> sys.stderr, "A VM with the name '{0}' does exist.".format(vmname)
exit(0)
main()

View File

@ -1,105 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# 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.
import os
import sys
from optparse import OptionParser
from qubes.qubes import QubesVmCollection
def main():
usage = "usage: %prog [options] <src-name> <new-name>\n"\
"Clones an existing VM by copying all its disk files"
parser = OptionParser(usage)
parser.add_option("-q", "--quiet", action="store_false", dest="verbose",
default=True)
parser.add_option("-p", "--path", dest="dir_path",
help="Specify path to the template directory")
parser.add_option("--force-root", action="store_true", dest="force_root",
default=False,
help="Force to run, even with root privileges")
parser.add_option("-P", "--pool", dest="pool_name",
help="Specify in to which storage pool to clone")
(options, args) = parser.parse_args()
if (len(args) != 2):
parser.error(
"You must specify at least the src and dst TemplateVM names!")
srcname = args[0]
dstname = args[1]
if hasattr(os, "geteuid") and 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_writing()
qvm_collection.load()
src_vm = qvm_collection.get_vm_by_name(srcname)
if src_vm is None:
print >> sys.stderr, \
"ERROR: A VM with the name '{0}' does not exist in the system." \
.format(srcname)
exit(1)
if options.pool_name is None:
pool_name = src_vm.pool_name
else:
pool_name = options.pool_name
if qvm_collection.get_vm_by_name(dstname) is not None:
print >> sys.stderr, \
"ERROR: A VM with the name '{0}' already exists in the system." \
.format(dstname)
exit(1)
if src_vm.is_disposablevm():
print >> sys.stderr, "ERROR: Clone not supported for this type of VM"
exit(1)
dst_vm = qvm_collection.add_new_vm(src_vm.__class__.__name__,
name=dstname, template=src_vm.template,
pool_name=pool_name,
dir_path=options.dir_path,
installed_by_rpm=False)
try:
dst_vm.clone_attrs(src_vm)
dst_vm.clone_disk_files(src_vm=src_vm, verbose=options.verbose)
except (IOError, OSError) as err:
print >> sys.stderr, "ERROR: {0}".format(err)
qvm_collection.pop(dst_vm.qid)
dst_vm.remove_from_disk()
exit(1)
qvm_collection.save()
qvm_collection.unlock_db()
main()

View File

@ -1,72 +0,0 @@
#!/bin/sh
if [ $# != 1 -a $# != 2 -o $1 == "--help" -o $1 == "-h" ] ; then
echo 'Usage: qvm-create-default-dvm templatename|--default-template|--used-template [script-name|--default-script]'
exit 1
fi
export ROOT=/var/lib/qubes/dvmdata/savefile-root
TEMPLATENAME=$1
if [ "$TEMPLATENAME" = --used-template ] ; then
if [ -e $ROOT ] ; then
TEMPLATENAME=$(readlink $ROOT | sed -e 's/.root.img//' -e 's/.*\///')
else
TEMPLATENAME=--default-template
fi
fi
if [ "$TEMPLATENAME" = --default-template ] ; then
TEMPLATENAME=$(qubes-prefs --get default-template)
if [ "X"$TEMPLATENAME = "X" ] ; then
echo No default template ?
exit 1
fi
fi
if [ -z "$2" -o "X""$2" = "X""--default-script" ] ; then
SCRIPTNAME="vm-default"
else
SCRIPTNAME=$2
fi
if ! [ -d "/var/lib/qubes/vm-templates/$TEMPLATENAME" ] ; then
echo /var/lib/qubes/vm-templates/$TEMPLATENAME is not a directory
exit 1
fi
DVMTMPL="$TEMPLATENAME"-dvm
DVMTMPLDIR="/var/lib/qubes/appvms/$DVMTMPL"
if ! [ -d "$DVMTMPLDIR" ] ; then
# unfortunately, currently there are reliability issues with save of a domain
# with multiple CPUs and/or more than 4000M RAM
if ! qvm-create --force-root --vcpus=1 --internal -t "$TEMPLATENAME" -l gray "$DVMTMPL" ; then exit 1 ; fi
MAXMEM=`qvm-prefs --force-root $DVMTMPL|grep ^maxmem|awk '{print $3}'`
if [ "$MAXMEM" -ge 4000 ]; then
qvm-prefs --force-root -s $DVMTMPL maxmem 4000
fi
fi
if ! /usr/lib/qubes/qubes-prepare-saved-domain.sh \
"$DVMTMPL" "/var/lib/qubes/appvms/$DVMTMPL/dvm-savefile" $SCRIPTNAME ; then
exit 1
fi
DEFAULT=/var/lib/qubes/dvmdata/default-savefile
CURRENT=/var/run/qubes/current-savefile
SHMDIR=/dev/shm/qubes
SHMCOPY=$SHMDIR/current-savefile
rm -f $ROOT $DEFAULT $CURRENT
ln -s "/var/lib/qubes/appvms/$DVMTMPL/dvm-savefile" $DEFAULT
ln -s "/var/lib/qubes/vm-templates/$TEMPLATENAME/root.img" $ROOT
if [ -f /var/lib/qubes/dvmdata/dont-use-shm ] ; then
ln -s $DEFAULT $CURRENT
else
mkdir -m 770 $SHMDIR 2>/dev/null
chgrp qubes $SHMDIR 2>/dev/null
rm -f $SHMCOPY
cp $DEFAULT $SHMCOPY || exit 1
chgrp qubes $SHMCOPY
chmod 660 $SHMCOPY
ln -s $SHMCOPY $CURRENT
fi
if [ $(whoami) = "root" ] ; then
chgrp qubes "$DVMTMPLDIR" "$DVMTMPLDIR"/*
chmod 660 "$DVMTMPLDIR"/*
chmod 770 "$DVMTMPLDIR"
fi

View File

@ -1,321 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2012 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 datetime
from qubes.qubes import QubesVmCollection
from optparse import OptionParser;
import subprocess
import sys
import re
import os
import socket
def parse_rule(args):
if len(args) < 2:
print >>sys.stderr, "ERROR: Rule must have at least address and protocol"
return None
address = args[0]
netmask = 32
proto = args[1]
port = args[2] if len(args) > 2 else None
port_end = None
unmask = address.split("/", 1)
if len(unmask) == 2:
address = unmask[0]
netmask = unmask[1]
if netmask.isdigit():
if re.match("^([0-9]{1,3}\.){3}[0-9]{1,3}$", address) is None:
print >>sys.stderr, "ERROR: Only IP is allowed when specyfying netmask"
return None
if netmask != "":
netmask = int(unmask[1])
if netmask < 0 or netmask > 32:
print >>sys.stderr, "ERROR: Invalid netmask"
return None
else:
print >>sys.stderr, "ERROR: Invalid netmask"
return None
if address[-1:] == ".":
address = address[:-1]
allowed = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
if not all(allowed.match(x) for x in address.split(".")):
print >>sys.stderr, "ERROR: Invalid hostname"
return None
proto_split = proto.split('/', 1)
if len(proto_split) == 2:
proto = proto_split[0]
port = proto_split[1]
if proto not in ['tcp', 'udp', 'any']:
print >>sys.stderr, "ERROR: Protocol must be one of: 'tcp', 'udp', 'any'"
return None
if proto != "any" and port is None:
print >>sys.stderr, "ERROR: Port required for protocol %s" % args[1]
return None
if port is not None:
port_range = port.split('-', 1)
if len(port_range) == 2:
port = port_range[0]
port_end = port_range[1]
if port.isdigit():
port = int(port)
else:
try:
port = socket.getservbyname(port)
except socket.error:
print >>sys.stderr, "ERROR: Invalid port/service name '%s'" % port
return None
if port_end is not None and not port_end.isdigit():
print >>sys.stderr, "ERROR: Invalid port '%s'" % port_end
return None
if port_end is not None:
port_end = int(port_end)
rule = {}
rule['address'] = address
rule['netmask'] = netmask
rule['proto'] = proto
rule['portBegin'] = port
rule['portEnd'] = port_end
return rule
def list_rules(rules, numeric=False):
fields = [ "num", "address", "proto", "port(s)" ]
rules_to_display = list()
counter = 1
for rule in rules:
parsed_rule = {
'num': "{0:>2}".format(counter),
'address': rule['address'] + ('/' + str(rule['netmask']) if rule['netmask'] < 32 else ""),
'proto': rule['proto'],
'port(s)': '',
}
if rule['proto'] in ['tcp', 'udp']:
parsed_rule['port(s)'] = str(rule['portBegin']) + \
('-' + str(rule['portEnd']) if rule['portEnd'] is not None else '')
if not numeric and rule['portBegin'] is not None and rule['portEnd'] is None:
try:
parsed_rule['port(s)'] = str(socket.getservbyport(rule['portBegin']))
except socket.error:
pass
if 'expire' in rule:
parsed_rule['expire'] = str(datetime.datetime.fromtimestamp(rule[
'expire']))
rules_to_display.append(parsed_rule)
counter += 1
fields_width = {}
for f in fields:
fields_width[f] = len(f)
for r in rules_to_display:
if len(r[f]) > fields_width[f]:
fields_width[f] = len(r[f])
# Display the header
s = ""
for f in fields:
fmt="{{0:-^{0}}}-+".format(fields_width[f] + 1)
s += fmt.format('-')
print s
s = ""
for f in fields:
fmt=" {{0:^{0}}} |".format(fields_width[f])
s += fmt.format(f)
print s
s = ""
for f in fields:
fmt="{{0:-^{0}}}-+".format(fields_width[f] + 1)
s += fmt.format('-')
print s
# And the content
for r in rules_to_display:
s = ""
for f in fields:
fmt=" {{0:<{0}}} |".format(fields_width[f])
s += fmt.format(r[f])
if 'expire' in r:
s += " <-- expires at %s" % r['expire']
print s
def display_firewall(conf, numeric=False):
print "Firewall policy: %s" % (
"ALLOW all traffic except" if conf['allow'] else "DENY all traffic except")
print "ICMP: %s" % ("ALLOW" if conf['allowIcmp'] else 'DENY')
print "DNS: %s" % ("ALLOW" if conf['allowDns'] else 'DENY')
print "Qubes yum proxy: %s" % ("ALLOW" if conf['allowYumProxy'] else 'DENY')
list_rules(conf['rules'], numeric)
def add_rule(conf, args):
rule = parse_rule(args)
if rule is None:
return False
conf['rules'].append(rule)
return True
def del_rule(conf, args):
if len(args) == 1 and args[0].isdigit():
rulenum = int(args[0])
if rulenum < 1 or rulenum > len(conf['rules']):
print >>sys.stderr, "ERROR: Rule number out of range"
return False
conf['rules'].pop(rulenum-1)
else:
rule = parse_rule(args)
#print "PARSED: %s" % str(rule)
#print "ALL: %s" % str(conf['rules'])
if rule is None:
return False
try:
conf['rules'].remove(rule)
except ValueError:
print >>sys.stderr, "ERROR: Rule not found"
return False
return True
def allow_deny_value(s):
value = None
if s == "allow":
value = True
elif s == "deny":
value = False
else:
print >>sys.stderr, 'ERROR: Only "allow" or "deny" allowed'
exit(1)
return value
def main():
usage = "usage: %prog [-n] <vm-name> [action] [rule spec]\n"
usage += " rule specification can be one of:\n"
usage += " address|hostname[/netmask] tcp|udp port[-port]\n"
usage += " address|hostname[/netmask] tcp|udp service_name\n"
usage += " address|hostname[/netmask] any\n"
parser = OptionParser (usage)
parser.add_option ("-l", "--list", dest="do_list", action="store_true", default=True,
help="List firewall settings (default action)")
parser.add_option ("-a", "--add", dest="do_add", action="store_true", default=False,
help="Add rule")
parser.add_option ("-d", "--del", dest="do_del", action="store_true", default=False,
help="Remove rule (given by number or by rule spec)")
parser.add_option ("-P", "--policy", dest="set_policy", action="store", default=None,
help="Set firewall policy (allow/deny)")
parser.add_option ("-i", "--icmp", dest="set_icmp", action="store", default=None,
help="Set ICMP access (allow/deny)")
parser.add_option ("-D", "--dns", dest="set_dns", action="store", default=None,
help="Set DNS access (allow/deny)")
parser.add_option ("-Y", "--yum-proxy", dest="set_yum_proxy", action="store", default=None,
help="Set access to Qubes yum proxy (allow/deny)")
parser.add_option ("-r", "--reload", dest="reload", action="store_true",
default=False, help="Reload firewall (implied by any "
"change action")
parser.add_option ("-n", "--numeric", dest="numeric", action="store_true", default=False,
help="Display port numbers instead of services (makes sense only with --list)")
parser.add_option ("--force-root", action="store_true", dest="force_root", default=False,
help="Force to run, even with root privileges")
(options, args) = parser.parse_args ()
if (len (args) < 1):
parser.error ("You must specify VM name!")
vmname = args[0]
args = args[1:]
if hasattr(os, "geteuid") and 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)
if options.do_add or options.do_del or options.set_policy or \
options.set_icmp or options.set_dns or options.set_yum_proxy:
options.do_list = False
qvm_collection = QubesVmCollection()
if options.do_list:
qvm_collection.lock_db_for_reading()
qvm_collection.load()
qvm_collection.unlock_db()
else:
qvm_collection.lock_db_for_writing()
qvm_collection.load()
vm = qvm_collection.get_vm_by_name(vmname)
if vm is None:
print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
exit(1)
changed = False
conf = vm.get_firewall_conf()
if options.set_policy:
conf['allow'] = allow_deny_value(options.set_policy)
changed = True
if options.set_icmp:
conf['allowIcmp'] = allow_deny_value(options.set_icmp)
changed = True
if options.set_dns:
conf['allowDns'] = allow_deny_value(options.set_dns)
changed = True
if options.set_yum_proxy:
conf['allowYumProxy'] = allow_deny_value(options.set_yum_proxy)
changed = True
if options.do_add:
changed = add_rule(conf, args)
elif options.do_del:
changed = del_rule(conf, args)
elif options.do_list and not options.reload:
if not vm.has_firewall():
print "INFO: This VM has no firewall rules set, below defaults are listed"
display_firewall(conf, options.numeric)
if changed:
vm.write_firewall_conf(conf)
qvm_collection.save()
if changed or options.reload:
if vm.is_running():
if vm.netvm is not None and vm.netvm.is_proxyvm():
vm.netvm.write_iptables_qubesdb_entry()
if not options.do_list:
qvm_collection.unlock_db()
main()

View File

@ -1,66 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# 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.
#
#
from qubes.qubes import QubesVmCollection
from qubes.qubes import QubesException
from qubes.qubesutils import parse_size
from optparse import OptionParser
import subprocess
import os
import re
import sys
qvm_run_path = "/usr/bin/qvm-run"
def main():
usage = "usage: %prog <vm-name> <size>"
parser = OptionParser (usage)
(options, args) = parser.parse_args ()
if (len (args) != 2):
parser.error ("You must specify VM name and new size!")
vmname = args[0]
size = args[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, "A VM with the name '{0}' does not exist in the system.".format(vmname)
exit(1)
size_bytes = parse_size(size)
try:
vm.resize_private_img(size_bytes)
except (IOError, OSError, QubesException) as err:
print >> sys.stderr, "ERROR: {0}".format(err)
exit (1)
exit (0)
main()

View File

@ -1,72 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2014 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.
#
#
from qubes.qubes import QubesVmCollection
from qubes.qubes import QubesException
from qubes.qubesutils import parse_size
from optparse import OptionParser
import subprocess
import os
import re
import sys
def main():
usage = "usage: %prog <vm-name> <size>"
parser = OptionParser (usage)
parser.add_option("--allow-start", action="store_true",
dest="allow_start", default=False,
help="Allow VM to be started to complete the operation")
(options, args) = parser.parse_args ()
if (len (args) != 2):
parser.error ("You must specify VM name and new size!")
vmname = args[0]
size = args[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, "A VM with the name '{0}' does not exist in the system.".format(vmname)
exit(1)
size_bytes = parse_size(size)
if not hasattr(vm, 'resize_root_img'):
print >> sys.stderr, "Operation not supported for this VM type"
exit(1)
try:
vm.resize_root_img(size_bytes, allow_start=options.allow_start)
except (IOError, OSError, QubesException) as err:
print >> sys.stderr, "ERROR: {0}".format(err)
exit (1)
exit (0)
main()

View File

@ -1,35 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# 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.
#
#
from qubes.qubes import QubesVmCollection,vmm
import sys
def main():
vmm.offline_mode = True
qvm_collection = QubesVmCollection()
if qvm_collection.check_if_storage_exists():
print >> sys.stderr, "Storage exists, not overwriting."
exit(1)
qvm_collection.create_empty_storage()
main()

View File

@ -1,141 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2010 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.
#
#
from qubes.qubes import QubesVmCollection
from optparse import OptionParser
import subprocess
import os
import sys
from qubes.qubes import vmm
import re
def find_devices_of_class(klass):
p = subprocess.Popen(["/sbin/lspci", "-mm", "-n"], stdout=subprocess.PIPE)
result = p.communicate()
retcode = p.returncode
if retcode != 0:
print "ERROR when executing lspci!"
raise IOError
rx_netdev = re.compile(r"^([0-9a-f]{2}:[0-9a-f]{2}.[0-9a-f]) \"" +
klass)
for dev in str(result[0]).splitlines():
match = rx_netdev.match(dev)
if match is not None:
dev_bdf = match.group(1)
assert dev_bdf is not None
yield dev_bdf
def main():
usage = "usage: %prog -l [options] <vm-name>\n"\
"usage: %prog -a [options] <vm-name> <device>\n"\
"usage: %prog -d [options] <vm-name> <device>\n"\
"List/set VM PCI devices."
parser = OptionParser (usage)
parser.add_option ("-l", "--list", action="store_true", dest="do_list", default=False)
parser.add_option ("-a", "--add", action="store_true", dest="do_add", default=False)
parser.add_option ("-d", "--delete", action="store_true", dest="do_delete", default=False)
parser.add_option("-C", "--add-class", action="store_true",
dest="do_add_class", default=False,
help="Add all devices of given class (net, usb)")
parser.add_option ("--offline-mode", dest="offline_mode",
action="store_true", default=False,
help="Offline mode")
(options, args) = parser.parse_args ()
if (len (args) < 1):
parser.error ("You must provide at least the vmname!")
vmname = args[0]
if options.do_list + options.do_add + options.do_delete + \
options.do_add_class > 1:
print >> sys.stderr, "Only one of -l -a -d -C is allowed!"
exit(1)
if options.offline_mode:
vmm.offline_mode = True
if options.do_add or options.do_delete or options.do_add_class:
qvm_collection = QubesVmCollection()
qvm_collection.lock_db_for_writing()
qvm_collection.load()
else:
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 or vm.qid not in qvm_collection:
print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
exit(1)
if options.do_add:
if len (args) < 2:
print >> sys.stderr, "You must specify the PCI device to add"
exit (1)
pci = args[1]
vm.pci_add(pci)
qvm_collection.save()
qvm_collection.unlock_db()
elif options.do_add_class:
if len(args) < 2:
print >> sys.stderr, "You must specify the PCI device class to add"
exit(1)
klass = args[1]
if klass == 'net':
devs = find_devices_of_class("02")
elif klass == 'usb':
devs = find_devices_of_class("0c03")
else:
print >> sys.stderr, "Supported classes: net, usb"
exit(1)
for dev in devs:
vm.pci_add(dev)
qvm_collection.save()
qvm_collection.unlock_db()
elif options.do_delete:
if len (args) < 2:
print >> sys.stderr, "You must specify the PCI device to delete"
exit (1)
pci = args[1]
vm.pci_remove(pci)
qvm_collection.save()
qvm_collection.unlock_db()
else:
# do_list
print str(vm.pcidevs)
main()

View File

@ -1,142 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# 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.
#
#
from qubes.qubes import QubesVmCollection
from qubes.qubes import QubesException
from optparse import OptionParser
import subprocess
import os
import time
import glob
import sys
def main():
usage = "usage: %prog [options] <template-name>"
parser = OptionParser (usage)
parser.add_option ("--force", action="store_true", dest="force", default=False,
help="Do not prompt for confirmation")
(options, args) = parser.parse_args ()
if (len (args) != 1):
parser.error ("You must specify TemplateVM name!")
vmname = args[0]
if hasattr(os, "geteuid") and os.geteuid() != 0:
print >> sys.stderr, "ERROR: This tool must be run as root!"
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, "A VM with the name '{0}' does not exist in the system.".format(vmname)
exit(1)
if not vm.is_template():
print >> sys.stderr, "A VM '{0}' is not template.".format(vmname)
exit(1)
if vm.is_running():
print >> sys.stderr, "You must stop VM first."
exit(1)
oldcow_img = vm.rootcow_img + '.old'
oldcow_stat = os.stat(oldcow_img)
oldcow_time_str = time.strftime("%F %T", time.gmtime(oldcow_stat.st_mtime))
root_stat = os.stat(vm.root_img)
old_dmdev = "/dev/mapper/snapshot-{0:x}:{1}-{2:x}:{3}".format(
root_stat[2], root_stat[1],
oldcow_stat[2], oldcow_stat[1])
snapshots = glob.glob('/dev/mapper/snapshot-{0:x}:{1}-*'.format(root_stat[2], root_stat[1]))
snapshot_present = False
for dev in snapshots:
if dev == old_dmdev:
snapshot_present = True
else:
print >> sys.stderr, "ERROR: You must shutdown all VMs running system older/newer than last good one."
exit(1)
root_blocks = os.path.getsize(vm.root_img)/512
if not snapshot_present:
p = subprocess.Popen (["/etc/xen/scripts/block-snapshot", "prepare",
"snapshot", "{0}:{1}".format(vm.root_img, oldcow_img)],
stdout=subprocess.PIPE)
result = p.communicate()
if result[0].strip() != old_dmdev:
print >> sys.stderr, "ERROR: Cannot create snapshot device ({0} != {1})".format(
result[0].strip(), old_dmdev)
exit(1)
print "INFO: Reverting template changes done at {0}".format(oldcow_time_str)
if not options.force:
prompt = raw_input ("Do you want to proceed? [y/N] ")
if not (prompt == "y" or prompt == "Y"):
exit (0)
p = subprocess.Popen(["/sbin/dmsetup", "table", old_dmdev], stdout=subprocess.PIPE)
result = p.communicate()
dm_table = result[0]
dm_table_elements = dm_table.split(' ')
if dm_table_elements[2] != 'snapshot':
print >> sys.stderr, "ERROR: Unexpected device-mapper type ({0}). Template changes reverting already running".format(dm_table_elements[2])
exit(1)
dm_table_elements[2] = 'snapshot-merge'
dm_table = ' '.join(dm_table_elements)
subprocess.check_call(["/sbin/dmsetup", "reload", old_dmdev, "--table", dm_table])
# Reload new table into LIVE slot
subprocess.check_call(["/sbin/dmsetup", "suspend", old_dmdev])
subprocess.check_call(["/sbin/dmsetup", "resume", old_dmdev])
# Wait to snapshot merge completed
while True:
p = subprocess.Popen(["/sbin/dmsetup", "status", old_dmdev], stdout=subprocess.PIPE)
result = p.communicate()
status_details = result[0].split(' ')
blocks_used = status_details[3].split('/')[0]
if int(blocks_used) == int(status_details[4]):
break
print "\r-> Reverting template changes: {0} of {1} left".format(blocks_used, root_blocks),
time.sleep(1)
print "\r-> Reverting template changes: done ".format(blocks_used, root_blocks)
dm_table_elements[2] = 'snapshot'
dm_table = ' '.join(dm_table_elements)
subprocess.check_call(["/sbin/dmsetup", "reload", old_dmdev, "--table", dm_table])
# Reload new table into LIVE slot
subprocess.check_call(["/sbin/dmsetup", "suspend", old_dmdev])
subprocess.check_call(["/sbin/dmsetup", "resume", old_dmdev])
subprocess.check_call(["/etc/xen/scripts/block-snapshot", "cleanup",
"snapshot", old_dmdev])
os.rename(oldcow_img, vm.rootcow_img)
exit(0)
main()

View File

@ -1,98 +0,0 @@
#!/usr/bin/python
# -*- encoding: utf8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2012 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.
#
#
from qubes.qubes import QubesVmCollection
from optparse import OptionParser;
import subprocess
import sys
import re
def do_list(vm):
max_len = 0
for s in vm.services.keys():
max_len = max(max_len, len(s))
fmt="{{0:<{0}}}: {{1}}".format(max_len)
for s in vm.services.keys():
print fmt.format (s, "Enabled" if vm.services[s] else "Disabled")
def main():
usage = "usage: %prog <vm-name> [action] [service]\n"
parser = OptionParser (usage)
parser.add_option ("-l", "--list", dest="do_list", action="store_true", default=True,
help="List services (default action)")
parser.add_option ("-e", "--enable", dest="set_enable", action="store_true", default=False,
help="Enable service")
parser.add_option ("-d", "--disable", dest="set_disable", action="store_true", default=False,
help="Disable service")
parser.add_option ("-D", "--default", dest="set_default", action="store_true", default=False,
help="Reset service to its default state (remove from the list)")
(options, args) = parser.parse_args ()
if (len (args) < 1):
parser.error ("You must specify VM name!")
vmname = args[0]
args = args[1:]
if options.set_enable or options.set_disable or options.set_default:
if (len(args) < 1):
parser.error("You must specify service name!")
options.do_list = False
qvm_collection = QubesVmCollection()
if options.do_list:
qvm_collection.lock_db_for_reading()
qvm_collection.load()
qvm_collection.unlock_db()
else:
qvm_collection.lock_db_for_writing()
qvm_collection.load()
vm = qvm_collection.get_vm_by_name(vmname)
if vm is None:
print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
exit(1)
changed = False
if options.do_list:
do_list(vm)
elif options.set_enable:
vm.services[args[0]] = True
changed = True
elif options.set_disable:
vm.services[args[0]] = False
changed = True
elif options.set_default:
if vm.services.has_key(args[0]):
vm.services.pop(args[0])
changed = True
if changed:
qvm_collection.save()
if not options.do_list:
qvm_collection.unlock_db()
main()

View File

@ -1,73 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# 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.
#
#
from qubes.qubes import QubesVmCollection,vmm
from qubes.qubes import QubesException
from optparse import OptionParser
import subprocess
import sys
def main():
usage = "usage: %prog [options] <vm-name>"
parser = OptionParser (usage)
parser.add_option ("--offline-mode", dest="offline_mode",
action="store_true", default=False,
help="Offline mode")
(options, args) = parser.parse_args ()
if (len (args) != 1):
parser.error ("You must specify VM name!")
vmname = args[0]
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, "A VM with the name '{0}' does not exist in the system.".format(vmname)
exit(1)
if not vm.is_template():
print >> sys.stderr, "A VM '{0}' is not template.".format(vmname)
exit(1)
if not vmm.offline_mode and vm.is_running():
print >> sys.stderr, "You must stop VM first."
exit(1)
try:
vm.verify_files()
vm.commit_changes()
except (IOError, OSError, QubesException) as err:
print >> sys.stderr, "ERROR: {0}".format(err)
exit (1)
exit (0)
main()

View File

@ -1,171 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2014 Matt McCutchen <matt@mattmccutchen.net>
# 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.
#
#
import os
import subprocess
import sys
import time
from qubes import qubes
from qubes import qubesutils
def is_dvm_up_to_date(tmpl, dvm_tmpl):
dvm_savefile_path = os.path.join(dvm_tmpl.dir_path, "dvm-savefile")
if not os.path.isfile(dvm_savefile_path):
return False
dvm_mtime = os.path.getmtime(dvm_savefile_path)
root_mtime = os.path.getmtime(tmpl.root_img)
if dvm_mtime < root_mtime:
return False
else:
return True
def main():
if len(sys.argv) != 2:
print >> sys.stderr, 'Usage: qvm-trim-template TEMPLATEVM_NAME'
sys.exit(1)
tvm_name = sys.argv[1]
qvm_collection = qubes.QubesVmCollection()
qvm_collection.lock_db_for_writing()
qvm_collection.load()
tvm = qvm_collection.get_vm_by_name(tvm_name)
if tvm is None:
print >> sys.stderr, 'VM \'{}\' does not exists'.format(tvm_name)
sys.exit(1)
if not tvm.is_template():
print >> sys.stderr, '{} is not template'.format(tvm_name)
sys.exit(1)
if tvm.is_running():
print >> sys.stderr, 'Please stop the TemplateVM first.'
sys.exit(1)
outdated_children = [c for c in qvm_collection.get_vms_based_on(tvm.qid) if
c.is_outdated()]
if outdated_children:
print >> sys.stderr, 'Please stop (or restart) the following outdated VMs based on the template first:\n%s' % ', '.join(
c.name for c in outdated_children)
sys.exit(1)
rootcow_old = tvm.rootcow_img + '.old'
print 'Disk usage before:'
subprocess.check_call(['du', tvm.root_img] + (
['--total', rootcow_old] if os.path.exists(rootcow_old) else []))
# root-cow.img.old is likely to be invalid once we trim root.img, so go ahead and delete it.
# (Note, root-cow.img should be logically empty because the TemplateVM is not running.)
if os.path.exists(rootcow_old):
os.remove(rootcow_old)
dvm_tmpl = qvm_collection.get_vm_by_name(tvm.name + '-dvm')
if dvm_tmpl is None:
touch_dvm_savefile = False
else:
touch_dvm_savefile = is_dvm_up_to_date(tvm, dvm_tmpl)
print >> sys.stderr, "Creating temporary VM..."
trim_vmname = "trim-{}".format(tvm_name[:31 - len('trim-')])
fstrim_vm = qvm_collection.get_vm_by_name(trim_vmname)
if fstrim_vm is not None:
if not fstrim_vm.internal:
print >>sys.stderr, \
"ERROR: VM '{}' already exists and is not marked as internal. " \
"Remove it manually."
fstrim_vm.remove_from_disk()
qvm_collection.pop(fstrim_vm.qid)
fstrim_vm = qvm_collection.add_new_vm(
"QubesAppVm",
template=tvm,
name=trim_vmname,
netvm=None,
internal=True,
)
if not fstrim_vm:
print >> sys.stderr, "ERROR: Failed to create new VM"
sys.exit(1)
fstrim_vm.create_on_disk()
fstrim_vm.start(start_guid=False, verbose=True)
print >> sys.stderr, "Performing fstrim now..."
fstrim_process = fstrim_vm.run("/bin/sh", user="root", passio_popen=True,
gui=False)
fstrim_process.stdin.write('''
until [ -r /dev/xvdi ]; do
sleep 1
done
mkdir /tmp/root
mount -o ro /dev/xvdi /tmp/root
fstrim -v /tmp/root
poweroff
''')
fstrim_process.stdin.close()
qubesutils.block_attach(qvm_collection, fstrim_vm,
{
'vm': 'dom0',
'device': tvm.root_img,
'mode': 'w',
},
mode='w',
frontend='xvdi')
# At this point, the trim should run and the vm should shut down by itself and
# detach the block device.
fstrim_process.wait()
print >> sys.stderr, "fstrim done, cleaning up..."
while fstrim_vm.is_running():
time.sleep(1)
fstrim_vm.remove_from_disk()
qvm_collection.pop(fstrim_vm.qid)
# if DispVM template was up to date, keep that state
if touch_dvm_savefile:
dvm_savefile_path = os.path.join(dvm_tmpl.dir_path, 'dvm-savefile')
os.utime(dvm_savefile_path, None)
# If this is default DispVM, make sure that tmpfs copy of the file
# (if enabled) also has mtime updated
if os.stat('/var/lib/qubes/dvmdata/default-savefile').st_ino == \
os.stat(dvm_savefile_path).st_ino:
os.utime('/var/run/qubes/current-savefile', None)
# do not save, all changes to qubes.xml should be reversed
qvm_collection.unlock_db()
print 'Disk usage after:'
subprocess.check_call(['du', tvm.root_img])
if __name__ == "__main__":
main()

View File

@ -1,141 +0,0 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2010 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.
#
#
from qubes.qubes import QubesVmCollection, QubesException
from qubes.qubesutils import usb_list,usb_attach,usb_detach,usb_detach_all,usb_check_attached
from optparse import OptionParser
import sys
import os
def main():
usage = "usage: %prog -l [options]\n"\
"usage: %prog -a [options] <vm-name> <device-vm-name>:<device>\n"\
"usage: %prog -d [options] <device-vm-name>:<device>\n"\
"List/set VM USB devices."
# "usage: %prog -d [options] <vm-name>\n"\
parser = OptionParser (usage)
parser.add_option ("-l", "--list", action="store_true", dest="do_list", default=False)
parser.add_option ("-a", "--attach", action="store_true", dest="do_attach", default=False)
parser.add_option ("-d", "--detach", action="store_true", dest="do_detach", default=False)
# parser.add_option ("-f", "--frontend", dest="frontend",
# help="Specify device id at destination VM [default: first unused]")
parser.add_option ("--no-auto-detach", dest="auto_detach", action="store_false", default=True,
help="Fail when device already connected to other VM")
parser.add_option ("--force-root", action="store_true", dest="force_root", default=False,
help="Force to run, even with root privileges")
(options, args) = parser.parse_args ()
if hasattr(os, "geteuid") and 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)
if options.do_list + options.do_attach + options.do_detach > 1:
print >> sys.stderr, "Only one of -l -a -d is allowed!"
exit (1)
qvm_collection = QubesVmCollection()
qvm_collection.lock_db_for_reading()
qvm_collection.load()
qvm_collection.unlock_db()
if options.do_attach:
if (len (args) != 2):
parser.error ("You must provide vm name and device!")
vm = qvm_collection.get_vm_by_name(args[0])
if vm is None:
parser.error ("Invalid VM name: %s" % args[0])
# FIXME: here we assume that device is always in form "domain:dev",
# which can be changed in the future
if args[1].find(":") < 0:
parser.error("Invalid device syntax: %s" % args[1])
backend_vm = qvm_collection.get_vm_by_name(args[1].split(":")[0])
if backend_vm is None:
parser.error("No such VM: {}".format(args[1].split(":")[0]))
dev_list = usb_list(qvm_collection, vm=backend_vm)
if not args[1] in dev_list.keys():
parser.error("Invalid device name: %s" % args[1])
dev = dev_list[args[1]]
assert backend_vm is not None
kwargs = {}
# if options.frontend:
# kwargs['frontend'] = options.frontend
kwargs['auto_detach'] = options.auto_detach
try:
usb_attach(qvm_collection, vm, dev, **kwargs)
except QubesException as e:
print >> sys.stderr, "ERROR: %s" % str(e)
sys.exit(1)
elif options.do_detach:
if (len (args) < 1):
parser.error ("You must provide device or vm name!")
if len(args) > 1:
parser.error ("Too many parameters")
# Check if provided name is VM
vm = qvm_collection.get_vm_by_name(args[0])
if vm is not None:
#kwargs = {}
#if options.frontend:
# kwargs['frontend'] = options.frontend
# usb_detach(vm, **kwargs)
#else:
usb_detach_all(qvm_collection, vm)
else:
# Maybe usbvm:device?
# FIXME: nasty copy-paste from attach code half a page above
# FIXME: here we assume that device is always in form "domain:dev",
# which can be changed in the future
if args[0].find(":") < 0:
parser.error("Invalid device syntax: %s" % args[0])
backend_vm = qvm_collection.get_vm_by_name(args[0].split(":")[0])
if backend_vm is None:
parser.error("No such VM: {}".format(args[0].split(":")[0]))
dev_list = usb_list(qvm_collection, vm=backend_vm)
if not args[0] in dev_list.keys():
parser.error("Invalid device name: %s" % args[0])
dev = dev_list[args[0]]
attached_to = usb_check_attached(qvm_collection, dev)
if attached_to is None:
print >> sys.stderr, "WARNING: Device not connected to any VM"
exit(0)
usb_detach(qvm_collection, attached_to, dev)
else:
if len(args) > 0:
parser.error("Too many parameters")
# do_list
for dev in usb_list(qvm_collection).values():
attached_to = dev['connected-to']
attached_to_str = ""
if attached_to:
attached_to_str = " (attached to %s)" % (attached_to.name)
print "%s\t%s%s" % (dev['name'], dev['desc'], attached_to_str)
exit (0)
main()

View File

@ -148,7 +148,6 @@ fi
systemctl --no-reload enable qubes-core.service >/dev/null 2>&1
systemctl --no-reload enable qubes-netvm.service >/dev/null 2>&1
systemctl --no-reload enable qubes-setupdvm.service >/dev/null 2>&1
# Conflicts with libxl stack, so disable it
systemctl --no-reload disable xend.service >/dev/null 2>&1
@ -404,20 +403,17 @@ fi
/usr/lib/qubes/unbind-pci-device.sh
/usr/lib/qubes/cleanup-dispvms
/usr/lib/qubes/qfile-daemon-dvm*
/usr/lib/qubes/block-cleaner-daemon.py*
/usr/lib/qubes/vusb-ctl.py*
/usr/lib/qubes/xl-qvm-usb-attach.py*
/usr/lib/qubes/xl-qvm-usb-detach.py*
/usr/lib/qubes/fix-dir-perms.sh
/usr/lib/qubes/startup-dvm.sh
/usr/lib/qubes/startup-misc.sh
/usr/lib/qubes/prepare-volatile-img.sh
/usr/libexec/qubes/qubes-notify-tools
/usr/libexec/qubes/qubes-notify-updates
%{_unitdir}/qubes-block-cleaner.service
%{_unitdir}/qubes-core.service
%{_unitdir}/qubes-setupdvm.service
%{_unitdir}/qubes-netvm.service
%{_unitdir}/qubes-qmemman.service
%{_unitdir}/qubes-vm@.service
@ -435,9 +431,6 @@ fi
/usr/share/qubes/templates/libvirt/devices/pci.xml
/usr/share/qubes/templates/libvirt/devices/net.xml
/usr/lib/tmpfiles.d/qubes.conf
/usr/lib/qubes/qubes-prepare-saved-domain.sh
/usr/lib/qubes/qubes-update-dispvm-savefile-with-progress.sh
/etc/xen/scripts/block.qubes
/etc/xen/scripts/block-snapshot
/etc/xen/scripts/block-origin
/etc/xen/scripts/vif-route-qubes
@ -456,7 +449,6 @@ fi
/etc/qubes-rpc/qubes.NotifyUpdates
%attr(2770,root,qubes) %dir /var/log/qubes
%attr(0770,root,qubes) %dir /var/run/qubes
/etc/xdg/autostart/qubes-guid.desktop
/etc/xdg/autostart/qrexec-policy-agent.desktop
/usr/share/doc/qubes/relaxng/*.rng