2013-01-20 21:44:13 +01:00
|
|
|
#!/usr/bin/python2
|
2011-03-14 10:43:09 +01:00
|
|
|
#
|
|
|
|
# The Qubes OS Project, http://www.qubes-os.org
|
|
|
|
#
|
|
|
|
# Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or
|
|
|
|
# modify it under the terms of the GNU General Public License
|
|
|
|
# as published by the Free Software Foundation; either version 2
|
|
|
|
# of the License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program; if not, write to the Free Software
|
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
#
|
|
|
|
#
|
|
|
|
import os
|
|
|
|
import dbus
|
|
|
|
import subprocess
|
|
|
|
import sys
|
2011-03-28 17:39:21 +02:00
|
|
|
import fcntl
|
2011-10-31 01:28:46 +01:00
|
|
|
import shutil
|
2011-03-14 10:43:09 +01:00
|
|
|
|
|
|
|
from qubes.qubes import QubesVmCollection
|
|
|
|
from qubes.qubes import QubesException
|
|
|
|
from qubes.qubes import QubesDaemonPidfile
|
2012-06-24 14:09:43 +02:00
|
|
|
from qubes.qubes import QubesDispVmLabels
|
2011-03-14 10:43:09 +01:00
|
|
|
from qubes.qmemman_client import QMemmanClient
|
|
|
|
|
|
|
|
current_savefile = '/var/run/qubes/current_savefile'
|
2011-06-08 03:36:02 +02:00
|
|
|
current_dvm_conf = '/var/run/qubes/current_dvm.conf'
|
2011-03-14 10:43:09 +01:00
|
|
|
notify_object = None
|
|
|
|
|
|
|
|
class QfileDaemonDvm:
|
|
|
|
def __init__(self, name):
|
|
|
|
self.name = name
|
|
|
|
|
|
|
|
def do_get_dvm(self):
|
|
|
|
qmemman_client = QMemmanClient()
|
|
|
|
if not qmemman_client.request_memory(400*1024*1024):
|
|
|
|
qmemman_client.close()
|
|
|
|
errmsg = 'Not enough memory to create DVM. '
|
|
|
|
errmsg +='Terminate some appVM and retry.'
|
2013-02-12 01:41:06 +01:00
|
|
|
if os.path.exists('/usr/bin/kdialog'):
|
|
|
|
subprocess.call(['/usr/bin/kdialog', '--sorry', errmsg])
|
|
|
|
else:
|
|
|
|
subprocess.call(['/usr/bin/zenity', '--warning', errmsg])
|
2011-03-14 10:43:09 +01:00
|
|
|
return None
|
|
|
|
|
2012-07-12 03:44:41 +02:00
|
|
|
self.tray_notify("Starting new DispVM...")
|
|
|
|
|
2011-03-14 10:43:09 +01:00
|
|
|
qvm_collection = QubesVmCollection()
|
|
|
|
qvm_collection.lock_db_for_writing()
|
|
|
|
qvm_collection.load()
|
|
|
|
|
|
|
|
vm = qvm_collection.get_vm_by_name(self.name)
|
|
|
|
if vm is None:
|
2011-07-09 17:56:40 +02:00
|
|
|
sys.stderr.write( 'Domain ' + self.name + ' does not exist ?')
|
2011-03-14 10:43:09 +01:00
|
|
|
qvm_collection.unlock_db()
|
|
|
|
qmemman_client.close()
|
|
|
|
return None
|
2012-06-24 14:09:43 +02:00
|
|
|
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]]
|
2011-03-14 10:43:09 +01:00
|
|
|
retcode = subprocess.call(['/usr/lib/qubes/qubes_restore',
|
|
|
|
current_savefile,
|
2011-06-08 03:36:02 +02:00
|
|
|
current_dvm_conf,
|
2012-11-13 04:02:49 +01:00
|
|
|
'-u', str(vm.default_user),
|
2012-06-24 14:09:43 +02:00
|
|
|
'-c', label.color,
|
|
|
|
'-i', label.icon,
|
|
|
|
'-l', str(label.index)])
|
2011-03-14 10:43:09 +01:00
|
|
|
qmemman_client.close()
|
|
|
|
if retcode != 0:
|
2013-02-12 01:41:06 +01:00
|
|
|
if os.path.exists('/usr/bin/kdialog'):
|
|
|
|
subprocess.call(['/usr/bin/kdialog', '--sorry', 'DisposableVM creation failed, see qubes_restore.log'])
|
|
|
|
else:
|
|
|
|
subprocess.call(['/usr/bin/zenity', '--warning', 'DisposableVM creation failed, see qubes_restore.log'])
|
2011-03-14 10:43:09 +01:00
|
|
|
qvm_collection.unlock_db()
|
|
|
|
return None
|
|
|
|
f = open('/var/run/qubes/dispVM_xid', 'r');
|
|
|
|
disp_xid = f.readline().rstrip('\n')
|
|
|
|
disp_name = f.readline().rstrip('\n')
|
|
|
|
disptempl = f.readline().rstrip('\n')
|
|
|
|
f.close()
|
|
|
|
vm_disptempl = qvm_collection.get_vm_by_name(disptempl);
|
|
|
|
if vm_disptempl is None:
|
|
|
|
sys.stderr.write( 'Domain ' + disptempl + ' does not exist ?')
|
|
|
|
qvm_collection.unlock_db()
|
|
|
|
return None
|
2011-07-09 17:52:47 +02:00
|
|
|
dispid=int(disp_name[4:])
|
2013-01-16 23:49:24 +01:00
|
|
|
dispvm=qvm_collection.add_new_disposablevm(disp_name, vm_disptempl.template, label=label, dispid=dispid, netvm=vm_disptempl.netvm)
|
2011-10-31 01:28:46 +01:00
|
|
|
# By default inherit firewall rules from calling VM
|
|
|
|
if os.path.exists(vm.firewall_conf):
|
|
|
|
disp_firewall_conf = '/var/run/qubes/%s-firewall.xml' % disp_name
|
|
|
|
shutil.copy(vm.firewall_conf, disp_firewall_conf)
|
|
|
|
dispvm.firewall_conf = disp_firewall_conf
|
2012-06-24 14:09:43 +02:00
|
|
|
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]
|
2011-03-14 10:43:09 +01:00
|
|
|
qvm_collection.save()
|
|
|
|
qvm_collection.unlock_db()
|
2011-07-09 17:54:23 +02:00
|
|
|
# Reload firewall rules
|
|
|
|
for vm in qvm_collection.values():
|
|
|
|
if vm.is_proxyvm() and vm.is_running():
|
|
|
|
vm.write_iptables_xenstore_entry()
|
2011-03-14 10:43:09 +01:00
|
|
|
|
|
|
|
return disp_name
|
|
|
|
|
|
|
|
def dvm_setup_ok(self):
|
|
|
|
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:
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
|
|
def tray_notify(self, str, timeout = 3000):
|
|
|
|
notify_object.Notify("Qubes", 0, "red", "Qubes", str, [], [], timeout, dbus_interface="org.freedesktop.Notifications")
|
|
|
|
|
|
|
|
def tray_notify_error(self, str, timeout = 3000):
|
|
|
|
notify_object.Notify("Qubes", 0, "dialog-error", "Qubes", str, [], [], timeout, dbus_interface="org.freedesktop.Notifications")
|
|
|
|
|
|
|
|
def get_dvm(self):
|
|
|
|
if not self.dvm_setup_ok():
|
2011-07-26 16:36:59 +02:00
|
|
|
if os.system("/usr/lib/qubes/qubes_update_dispvm_savefile_with_progress.sh >/dev/null </dev/null" ) != 0:
|
2011-03-14 10:43:09 +01:00
|
|
|
self.tray_notify_error("DVM savefile creation failed")
|
|
|
|
return None
|
|
|
|
return self.do_get_dvm()
|
|
|
|
|
|
|
|
def remove_disposable_from_qdb(self, 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
|
|
|
|
qvm_collection.pop(vm.qid)
|
|
|
|
qvm_collection.save()
|
|
|
|
qvm_collection.unlock_db()
|
|
|
|
|
|
|
|
def main():
|
|
|
|
global notify_object
|
2011-07-06 12:32:20 +02:00
|
|
|
exec_index = sys.argv[1]
|
|
|
|
src_vmname = sys.argv[2]
|
2011-07-06 18:34:00 +02:00
|
|
|
user = sys.argv[3]
|
2012-06-24 14:09:43 +02:00
|
|
|
#accessed directly by get_dvm()
|
|
|
|
# sys.argv[4] - override label
|
|
|
|
# sys.argv[5] - override firewall
|
2011-07-06 18:34:00 +02:00
|
|
|
|
2011-03-14 10:43:09 +01:00
|
|
|
notify_object = dbus.SessionBus().get_object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
|
2011-07-06 12:32:20 +02:00
|
|
|
qfile = QfileDaemonDvm(src_vmname)
|
2011-03-28 17:39:21 +02:00
|
|
|
lockf = open("/var/run/qubes/qfile-daemon-dvm.lock", 'a')
|
2011-06-29 19:32:49 +02:00
|
|
|
fcntl.fcntl(lockf, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
|
2011-03-28 17:39:21 +02:00
|
|
|
fcntl.flock(lockf, fcntl.LOCK_EX)
|
2011-03-14 10:43:09 +01:00
|
|
|
dispname = qfile.get_dvm()
|
2011-03-28 17:39:21 +02:00
|
|
|
lockf.close()
|
2011-03-14 10:43:09 +01:00
|
|
|
if dispname is not None:
|
2011-07-06 12:32:20 +02:00
|
|
|
subprocess.call(['/usr/lib/qubes/qrexec_client', '-d', dispname,
|
2011-07-09 13:11:32 +02:00
|
|
|
user+':exec /usr/lib/qubes/qubes_rpc_multiplexer ' + exec_index + " " + src_vmname])
|
2011-06-01 23:44:06 +02:00
|
|
|
subprocess.call(['/usr/sbin/xl', 'destroy', dispname])
|
2011-03-14 10:43:09 +01:00
|
|
|
qfile.remove_disposable_from_qdb(dispname)
|
|
|
|
|
|
|
|
main()
|
2011-06-01 23:44:06 +02:00
|
|
|
|