123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- #!/usr/bin/python2
- #
- # 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
- import fcntl
- import shutil
- import time
- from qubes.qubes import QubesVmCollection
- from qubes.qubes import QubesException
- from qubes.qubes import QubesDaemonPidfile
- from qubes.qubes import QubesDispVmLabels
- from qubes.qmemman_client import QMemmanClient
- current_savefile = '/var/run/qubes/current-savefile'
- current_dvm_conf = '/var/run/qubes/current-dvm.conf'
- 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.'
- if os.path.exists('/usr/bin/kdialog'):
- subprocess.call(['/usr/bin/kdialog', '--sorry', errmsg])
- else:
- subprocess.call(['/usr/bin/zenity', '--warning', '--text', errmsg])
- return None
- self.tray_notify("Starting new DispVM...")
- 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:
- sys.stderr.write( 'Domain ' + self.name + ' does not exist ?')
- qvm_collection.unlock_db()
- qmemman_client.close()
- 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]]
- print >>sys.stderr, "time=%s, starting qubes-restore" % (str(time.time()))
- retcode = subprocess.call(['/usr/lib/qubes/qubes-restore',
- current_savefile,
- current_dvm_conf,
- '-u', str(vm.default_user),
- '-c', label.color,
- '-i', label.icon_path,
- '-l', str(label.index)])
- qmemman_client.close()
- if retcode != 0:
- tray_notify_error('DisposableVM creation failed, see qubes-restore.log')
- 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()
- print >>sys.stderr, "time=%s, adding to qubes.xml" % (str(time.time()))
- 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
- dispid=int(disp_name[4:])
- dispvm=qvm_collection.add_new_disposablevm(disp_name, vm_disptempl.template, label=label, dispid=dispid, netvm=vm_disptempl.netvm)
- # 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
- 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]
- qvm_collection.save()
- 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_xenstore_entry()
- 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:
- template_name = os.path.basename(os.path.dirname(os.readlink(dvmdata_dir+'savefile-root')))
- if subprocess.call(["xl", "domid", template_name]) == 0:
- self.tray_notify("For optimum performance, you should not start DispVM when its template is running.")
- return False
- return True
- def tray_notify(self, str, timeout = 3000):
- if notify_object:
- notify_object.Notify("Qubes", 0, "red", "Qubes", str, [], [], timeout, dbus_interface="org.freedesktop.Notifications")
- def tray_notify_error(self, str, timeout = 3000):
- if notify_object:
- 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():
- if os.system("/usr/lib/qubes/qubes-update-dispvm-savefile-with-progress.sh >/dev/null </dev/null" ) != 0:
- 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
- exec_index = sys.argv[1]
- 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()))
- try:
- notify_object = dbus.SessionBus().get_object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
- except dbus.DBusException as e:
- print >>sys.stderr, "Warning: notification service not available: %s" % str(e)
- notify_object = None
- print >>sys.stderr, "time=%s, creating DispVM" % (str(time.time()))
- qfile = QfileDaemonDvm(src_vmname)
- lockf = open("/var/run/qubes/qfile-daemon-dvm.lock", 'a')
- fcntl.fcntl(lockf, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
- fcntl.flock(lockf, fcntl.LOCK_EX)
- dispname = qfile.get_dvm()
- lockf.close()
- if dispname is not None:
- print >>sys.stderr, "time=%s, starting VM process" % (str(time.time()))
- subprocess.call(['/usr/lib/qubes/qrexec-client', '-d', dispname,
- user+':exec /usr/lib/qubes/qubes-rpc-multiplexer ' + exec_index + " " + src_vmname])
- subprocess.call(['/usr/sbin/xl', 'destroy', dispname])
- qfile.remove_disposable_from_qdb(dispname)
- main()
-
|