183 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			183 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/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', 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:
 | 
						|
            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'])
 | 
						|
            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:
 | 
						|
            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():
 | 
						|
            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()))
 | 
						|
    notify_object = dbus.SessionBus().get_object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
 | 
						|
    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()
 | 
						|
 
 |