Преглед на файлове

Implemented Firewall Rules Editor

Tomasz Sterna преди 13 години
родител
ревизия
f8aadd7998
променени са 7 файла, в които са добавени 828 реда и са изтрити 1 реда
  1. 2 0
      Makefile
  2. 147 0
      editfwrulesdlg.ui
  3. 239 0
      newfwruledlg.ui
  4. 269 0
      qubesmanager/firewall.py
  5. 17 1
      qubesmanager/main.py
  6. 66 0
      qubesmanager/ui_editfwrulesdlg.py
  7. 88 0
      qubesmanager/ui_newfwruledlg.py

+ 2 - 0
Makefile

@@ -13,6 +13,8 @@ rpms:
 res:
 	pyrcc4 -o qubesmanager/qrc_resources.py resources.qrc
 	pyuic4 -o qubesmanager/ui_newappvmdlg.py newappvmdlg.ui
+	pyuic4 -o qubesmanager/ui_editfwrulesdlg.py editfwrulesdlg.ui
+	pyuic4 -o qubesmanager/ui_newfwruledlg.py newfwruledlg.ui
 
 update-repo:
 	ln -f $(RPMS_DIR)/x86_64/qubes-manager-*.rpm ../yum/r1/dom0/rpm/

+ 147 - 0
editfwrulesdlg.ui

@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>EditFwRulesDlg</class>
+ <widget class="QDialog" name="EditFwRulesDlg">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>500</width>
+    <height>280</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Edit Firewall Rules</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_3">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="sizeConstraint">
+      <enum>QLayout::SetMaximumSize</enum>
+     </property>
+     <item>
+      <widget class="QTreeView" name="rulesTreeView">
+       <property name="rootIsDecorated">
+        <bool>false</bool>
+       </property>
+       <property name="uniformRowHeights">
+        <bool>false</bool>
+       </property>
+       <property name="itemsExpandable">
+        <bool>false</bool>
+       </property>
+       <property name="allColumnsShowFocus">
+        <bool>true</bool>
+       </property>
+       <property name="expandsOnDoubleClick">
+        <bool>true</bool>
+       </property>
+       <attribute name="headerDefaultSectionSize">
+        <number>40</number>
+       </attribute>
+       <attribute name="headerStretchLastSection">
+        <bool>false</bool>
+       </attribute>
+       <attribute name="headerDefaultSectionSize">
+        <number>40</number>
+       </attribute>
+       <attribute name="headerStretchLastSection">
+        <bool>false</bool>
+       </attribute>
+      </widget>
+     </item>
+     <item>
+      <layout class="QVBoxLayout" name="verticalLayout">
+       <item>
+        <widget class="QPushButton" name="newRuleButton">
+         <property name="text">
+          <string>&amp;New</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="editRuleButton">
+         <property name="text">
+          <string>&amp;Edit</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="deleteRuleButton">
+         <property name="text">
+          <string>&amp;Delete</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>newRuleButton</tabstop>
+  <tabstop>editRuleButton</tabstop>
+  <tabstop>deleteRuleButton</tabstop>
+  <tabstop>rulesTreeView</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>EditFwRulesDlg</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>EditFwRulesDlg</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>

+ 239 - 0
newfwruledlg.ui

@@ -0,0 +1,239 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>NewFwRuleDlg</class>
+ <widget class="QDialog" name="NewFwRuleDlg">
+  <property name="windowModality">
+   <enum>Qt::NonModal</enum>
+  </property>
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>311</width>
+    <height>202</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>New Firewall Rule</string>
+  </property>
+  <property name="modal">
+   <bool>true</bool>
+  </property>
+  <widget class="QDialogButtonBox" name="buttonBox">
+   <property name="geometry">
+    <rect>
+     <x>30</x>
+     <y>160</y>
+     <width>271</width>
+     <height>32</height>
+    </rect>
+   </property>
+   <property name="orientation">
+    <enum>Qt::Horizontal</enum>
+   </property>
+   <property name="standardButtons">
+    <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+   </property>
+  </widget>
+  <widget class="QLabel" name="label">
+   <property name="geometry">
+    <rect>
+     <x>10</x>
+     <y>10</y>
+     <width>62</width>
+     <height>17</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>Name</string>
+   </property>
+  </widget>
+  <widget class="QGroupBox" name="groupBox">
+   <property name="geometry">
+    <rect>
+     <x>10</x>
+     <y>40</y>
+     <width>291</width>
+     <height>121</height>
+    </rect>
+   </property>
+   <property name="title">
+    <string/>
+   </property>
+   <widget class="QLabel" name="label_2">
+    <property name="geometry">
+     <rect>
+      <x>10</x>
+      <y>10</y>
+      <width>62</width>
+      <height>17</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>Address</string>
+    </property>
+   </widget>
+   <widget class="QLabel" name="label_3">
+    <property name="geometry">
+     <rect>
+      <x>190</x>
+      <y>10</y>
+      <width>62</width>
+      <height>17</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>Netmask</string>
+    </property>
+   </widget>
+   <widget class="QCheckBox" name="allowCheckBox">
+    <property name="geometry">
+     <rect>
+      <x>200</x>
+      <y>80</y>
+      <width>71</width>
+      <height>23</height>
+     </rect>
+    </property>
+    <property name="sizePolicy">
+     <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+      <horstretch>0</horstretch>
+      <verstretch>0</verstretch>
+     </sizepolicy>
+    </property>
+    <property name="text">
+     <string>Allow</string>
+    </property>
+   </widget>
+   <widget class="QLineEdit" name="addressEdit">
+    <property name="geometry">
+     <rect>
+      <x>10</x>
+      <y>30</y>
+      <width>171</width>
+      <height>27</height>
+     </rect>
+    </property>
+   </widget>
+   <widget class="QLabel" name="label_4">
+    <property name="geometry">
+     <rect>
+      <x>10</x>
+      <y>62</y>
+      <width>31</width>
+      <height>21</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>Port</string>
+    </property>
+   </widget>
+   <widget class="QLabel" name="label_5">
+    <property name="geometry">
+     <rect>
+      <x>123</x>
+      <y>62</y>
+      <width>16</width>
+      <height>21</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>-</string>
+    </property>
+   </widget>
+   <widget class="QComboBox" name="netmaskComboBox">
+    <property name="geometry">
+     <rect>
+      <x>190</x>
+      <y>30</y>
+      <width>84</width>
+      <height>27</height>
+     </rect>
+    </property>
+   </widget>
+   <widget class="QSpinBox" name="portBeginSpinBox">
+    <property name="geometry">
+     <rect>
+      <x>50</x>
+      <y>60</y>
+      <width>71</width>
+      <height>27</height>
+     </rect>
+    </property>
+    <property name="maximum">
+     <number>65535</number>
+    </property>
+    <property name="value">
+     <number>0</number>
+    </property>
+   </widget>
+   <widget class="QSpinBox" name="portEndSpinBox">
+    <property name="geometry">
+     <rect>
+      <x>130</x>
+      <y>60</y>
+      <width>71</width>
+      <height>27</height>
+     </rect>
+    </property>
+    <property name="maximum">
+     <number>65535</number>
+    </property>
+   </widget>
+  </widget>
+  <widget class="QLineEdit" name="nameEdit">
+   <property name="geometry">
+    <rect>
+     <x>60</x>
+     <y>4</y>
+     <width>241</width>
+     <height>27</height>
+    </rect>
+   </property>
+  </widget>
+ </widget>
+ <tabstops>
+  <tabstop>nameEdit</tabstop>
+  <tabstop>addressEdit</tabstop>
+  <tabstop>netmaskComboBox</tabstop>
+  <tabstop>portBeginSpinBox</tabstop>
+  <tabstop>portEndSpinBox</tabstop>
+  <tabstop>allowCheckBox</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>NewFwRuleDlg</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>174</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>201</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>NewFwRuleDlg</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>300</x>
+     <y>180</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>201</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>

+ 269 - 0
qubesmanager/firewall.py

@@ -0,0 +1,269 @@
+#
+# The Qubes OS Project, http://www.qubes-os.org
+#
+# Copyright (C) 2011  Tomasz Sterna <tomek@xiaoka.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
+import os
+import xml.etree.ElementTree
+
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+
+from qubes.qubes import QubesVmCollection
+from qubes.qubes import QubesException
+from qubes.qubes import qubes_store_filename
+from qubes.qubes import QubesVmLabels
+from qubes.qubes import dry_run
+from qubes.qubes import qubes_guid_path
+
+import ui_editfwrulesdlg
+import ui_newfwruledlg
+
+class EditFwRulesDlg (QDialog, ui_editfwrulesdlg.Ui_EditFwRulesDlg):
+    def __init__(self, parent = None):
+        super (EditFwRulesDlg, self).__init__(parent)
+        self.setupUi(self)
+        self.newRuleButton.clicked.connect(self.new_rule_button_pressed)
+        self.deleteRuleButton.clicked.connect(self.delete_rule_button_pressed)
+
+    def set_model(self, model):
+        self.__model = model
+        self.rulesTreeView.setModel(model)
+        self.rulesTreeView.header().setResizeMode(QHeaderView.ResizeToContents)
+        self.rulesTreeView.header().setResizeMode(0, QHeaderView.Stretch)
+
+    def new_rule_button_pressed(self):
+        dialog = NewFwRuleDlg()
+
+        if dialog.exec_():
+            name = dialog.nameEdit.text()
+            allow = dialog.allowCheckBox.isChecked()
+            address = dialog.addressEdit.text()
+            netmask = dialog.netmasks[dialog.netmaskComboBox.currentIndex()]
+            portBegin = dialog.portBeginSpinBox.value()
+            portEnd   = dialog.portEndSpinBox.value()
+            if portEnd <= portBegin:
+                portEnd = None
+
+            if portBegin == 0 and portEnd is None:
+                return
+
+            if name == "":
+                QMessageBox.warning(None, "Incorrect name", "You need to name the rule.")
+                return
+
+            if address == "":
+                QMessageBox.warning(None, "Incorrect address", "Pleas give an address for the rule.")
+                return
+
+            self.__model.appendChild(QubesFirewallRuleItem(name, allow, address, netmask, portBegin, portEnd))
+
+    def delete_rule_button_pressed(self):
+        for i in set([index.row() for index in self.rulesTreeView.selectedIndexes()]):
+            self.__model.removeChild(i)
+
+class NewFwRuleDlg (QDialog, ui_newfwruledlg.Ui_NewFwRuleDlg):
+    def __init__(self, parent = None):
+        super (NewFwRuleDlg, self).__init__(parent)
+        self.setupUi(self)
+
+        self.netmasks = [ 32, 24, 16, 0 ]
+        for mask in self.netmasks:
+            self.netmaskComboBox.addItem(str(mask))
+
+class QubesFirewallRuleItem(object):
+    def __init__(self, name = str(), allow = bool(), address = str(), netmask = 32, portBegin = 0, portEnd = None):
+        self.__name = name
+        self.__allow = allow
+        self.__address = address
+        self.__netmask = netmask
+        self.__portBegin = portBegin
+        self.__portEnd = portEnd
+
+    @property
+    def name(self):
+        return self.__name
+
+    @property
+    def allow(self):
+        return self.__allow
+
+    @property
+    def address(self):
+        return self.__address
+
+    @property
+    def netmask(self):
+        return self.__netmask
+
+    @property
+    def portBegin(self):
+        return self.__portBegin
+
+    @property
+    def portEnd(self):
+        return self.__portEnd
+
+    def hasChildren(self):
+        return False
+
+class QubesFirewallRulesModel(QAbstractItemModel):
+    def __init__(self, parent=None):
+        QAbstractItemModel.__init__(self, parent)
+
+        self.__columnValues = {
+                0: lambda x: self.children[x].name,
+                1: lambda x: self.children[x].address,
+                2: lambda x: "/{0}".format(self.children[x].netmask),
+                3: lambda x: "{0}-{1}".format(self.children[x].portBegin, self.children[x].portEnd) if self.children[x].portEnd is not None \
+                        else self.children[x].portBegin,
+                4: lambda x: "ALLOW" if self.children[x].allow else "DENY",
+        }
+        self.__columnNames = {
+                0: "Name",
+                1: "Address",
+                2: "Mask",
+                3: "Port(s)",
+                4: "Allow",
+        }
+
+    def set_vm(self, vm):
+        self.__vm = vm
+
+        self.clearChildren()
+
+        root = vm.get_firewall_conf()
+        for element in root:
+            try:
+                kwargs = { "allow": element.tag=="allow" }
+                attr_list = ("name", "address", "netmask", "port", "toport")
+
+                for attribute in attr_list:
+                    kwargs[attribute] = element.get(attribute)
+
+                kwargs["netmask"] = int(kwargs["netmask"])
+                kwargs["portBegin"] = int(kwargs["port"])
+                if kwargs["toport"] is not None:
+                    kwargs["portEnd"] = int(kwargs["toport"])
+                del(kwargs["port"])
+                del(kwargs["toport"])
+
+                self.appendChild(QubesFirewallRuleItem(**kwargs))
+
+            except (ValueError, LookupError) as err:
+                print "{0}: load error: {1}".format(
+                        os.path.basename(sys.argv[0]), err)
+                return False
+
+        return True
+
+    def apply_rules(self):
+        assert self.__vm is not None
+
+        root = xml.etree.ElementTree.Element(
+                "QubesFirwallRules",
+                policy="allow"
+        )
+
+        for rule in self.children:
+            element = xml.etree.ElementTree.Element(
+                    "allow" if rule.allow else "deny",
+                    name=rule.name,
+                    address=rule.address,
+                    netmask=str(rule.netmask),
+                    port=str(rule.portBegin),
+            )
+            if rule.portEnd is not None:
+                element.set("toport", str(rule.portEnd)) 
+            root.append(element)
+
+        tree = xml.etree.ElementTree.ElementTree(root)
+
+        try:
+            self.__vm.write_firewall_conf(tree)
+        except EnvironmentError as err:
+            print "{0}: save error: {1}".format(
+                    os.path.basename(sys.argv[0]), err)
+            return False
+
+        return True
+
+    def index(self, row, column, parent=QModelIndex()):
+        if not self.hasIndex(row, column, parent):
+            return QModelIndex()
+
+        return self.createIndex(row, column, self.children[row])
+
+    def parent(self, child):
+        return QModelIndex()
+
+    def rowCount(self, parent=QModelIndex()):
+        return len(self)
+
+    def columnCount(self, parent=QModelIndex()):
+        return len(self.__columnValues)
+
+    def hasChildren(self, index=QModelIndex()):
+        parentItem = index.internalPointer()
+        if parentItem is not None:
+            return parentItem.hasChildren()
+        else:
+            return True
+
+    def data(self, index, role=Qt.DisplayRole):
+        if index.isValid() and role == Qt.DisplayRole:
+            return self.__columnValues[index.column()](index.row())
+
+        return QVariant()
+
+    def headerData(self, section, orientation, role=Qt.DisplayRole):
+        if section < len(self.__columnNames) \
+                and orientation == Qt.Horizontal and role == Qt.DisplayRole:
+                    return self.__columnNames[section]
+
+        return QVariant()
+
+    @property
+    def children(self):
+        return self.__children
+
+    def appendChild(self, child):
+        row = len(self)
+        self.beginInsertRows(QModelIndex(), row, row)
+        self.children.append(child)
+        self.endInsertRows()
+        index = self.createIndex(row, 0, child)
+        self.dataChanged.emit(index, index)
+
+    def removeChild(self, i):
+        if i >= len(self):
+            return
+
+        self.beginRemoveRows(QModelIndex(), i, i)
+        del self.children[i]
+        self.endRemoveRows()
+        index = self.createIndex(i, 0)
+        self.dataChanged.emit(index, index)
+        
+    def clearChildren(self):
+        self.__children = list()
+
+    def __len__(self):
+        return len(self.children)

+ 17 - 1
qubesmanager/main.py

@@ -36,6 +36,8 @@ from qubes.qubes import QubesHost
 import qubesmanager.qrc_resources
 import ui_newappvmdlg
 
+from firewall import EditFwRulesDlg, QubesFirewallRulesModel
+
 from pyinotify import WatchManager, Notifier, ThreadedNotifier, EventsCodes, ProcessEvent
 
 import subprocess
@@ -328,6 +330,9 @@ class VmManagerWindow(QMainWindow):
         self.action_showcpuload = self.createAction ("Show/Hide CPU Load chart", slot=self.showcpuload, checkable=True,
                                              icon="showcpuload", tip="Show/Hide CPU Load chart")
 
+        self.action_editfwrules = self.createAction ("Edit VM Firewall rules", slot=self.edit_fw_rules,
+                                             icon="showcpuload", tip="Edit VM Firewall rules")
+
 
         self.action_removevm.setDisabled(True)
         self.action_resumevm.setDisabled(True)
@@ -341,7 +346,8 @@ class VmManagerWindow(QMainWindow):
         self.toolbar.setFloatable(False)
         self.addActions (self.toolbar, (self.action_createvm, self.action_removevm,
                                    None,
-                                   self.action_resumevm, self.action_pausevm, self.action_shutdownvm, self.action_updatevm,
+                                   self.action_resumevm, self.action_pausevm, self.action_shutdownvm,
+                                   self.action_updatevm, self.action_editfwrules,
                                    None,
                                    self.action_showcpuload,
                                    ))
@@ -491,6 +497,7 @@ class VmManagerWindow(QMainWindow):
         #self.action_resumevm.setEnabled(not vm.is_running())
         #self.action_pausevm.setEnabled(vm.is_running() and vm.qid != 0)
         self.action_shutdownvm.setEnabled(vm.is_running() and vm.qid != 0)
+        self.action_editfwrules.setEnabled(vm.is_networked() and (vm.is_appvm() or vm.is_disposablevm()))
 
     def closeEvent (self, event):
         self.hide()
@@ -684,6 +691,15 @@ class VmManagerWindow(QMainWindow):
     def showcpuload(self):
         pass
 
+    def edit_fw_rules(self):
+        vm = self.get_selected_vm()
+        dialog = EditFwRulesDlg()
+        model = QubesFirewallRulesModel()
+        model.set_vm(vm)
+        dialog.set_model(model)
+
+        if dialog.exec_():
+            model.apply_rules()
                    
 class QubesTrayIcon(QSystemTrayIcon):
     def __init__(self, icon):

+ 66 - 0
qubesmanager/ui_editfwrulesdlg.py

@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'editfwrulesdlg.ui'
+#
+# Created: Wed Feb 16 20:55:59 2011
+#      by: PyQt4 UI code generator 4.7.3
+#
+# WARNING! All changes made in this file will be lost!
+
+from PyQt4 import QtCore, QtGui
+
+class Ui_EditFwRulesDlg(object):
+    def setupUi(self, EditFwRulesDlg):
+        EditFwRulesDlg.setObjectName("EditFwRulesDlg")
+        EditFwRulesDlg.resize(500, 280)
+        self.verticalLayout_3 = QtGui.QVBoxLayout(EditFwRulesDlg)
+        self.verticalLayout_3.setObjectName("verticalLayout_3")
+        self.horizontalLayout = QtGui.QHBoxLayout()
+        self.horizontalLayout.setSizeConstraint(QtGui.QLayout.SetMaximumSize)
+        self.horizontalLayout.setObjectName("horizontalLayout")
+        self.rulesTreeView = QtGui.QTreeView(EditFwRulesDlg)
+        self.rulesTreeView.setRootIsDecorated(False)
+        self.rulesTreeView.setUniformRowHeights(False)
+        self.rulesTreeView.setItemsExpandable(False)
+        self.rulesTreeView.setAllColumnsShowFocus(True)
+        self.rulesTreeView.setExpandsOnDoubleClick(True)
+        self.rulesTreeView.setObjectName("rulesTreeView")
+        self.rulesTreeView.header().setDefaultSectionSize(40)
+        self.rulesTreeView.header().setStretchLastSection(False)
+        self.horizontalLayout.addWidget(self.rulesTreeView)
+        self.verticalLayout = QtGui.QVBoxLayout()
+        self.verticalLayout.setObjectName("verticalLayout")
+        self.newRuleButton = QtGui.QPushButton(EditFwRulesDlg)
+        self.newRuleButton.setObjectName("newRuleButton")
+        self.verticalLayout.addWidget(self.newRuleButton)
+        self.editRuleButton = QtGui.QPushButton(EditFwRulesDlg)
+        self.editRuleButton.setObjectName("editRuleButton")
+        self.verticalLayout.addWidget(self.editRuleButton)
+        self.deleteRuleButton = QtGui.QPushButton(EditFwRulesDlg)
+        self.deleteRuleButton.setObjectName("deleteRuleButton")
+        self.verticalLayout.addWidget(self.deleteRuleButton)
+        spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
+        self.verticalLayout.addItem(spacerItem)
+        self.horizontalLayout.addLayout(self.verticalLayout)
+        self.verticalLayout_3.addLayout(self.horizontalLayout)
+        self.buttonBox = QtGui.QDialogButtonBox(EditFwRulesDlg)
+        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
+        self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
+        self.buttonBox.setObjectName("buttonBox")
+        self.verticalLayout_3.addWidget(self.buttonBox)
+
+        self.retranslateUi(EditFwRulesDlg)
+        QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), EditFwRulesDlg.reject)
+        QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("accepted()"), EditFwRulesDlg.accept)
+        QtCore.QMetaObject.connectSlotsByName(EditFwRulesDlg)
+        EditFwRulesDlg.setTabOrder(self.newRuleButton, self.editRuleButton)
+        EditFwRulesDlg.setTabOrder(self.editRuleButton, self.deleteRuleButton)
+        EditFwRulesDlg.setTabOrder(self.deleteRuleButton, self.rulesTreeView)
+        EditFwRulesDlg.setTabOrder(self.rulesTreeView, self.buttonBox)
+
+    def retranslateUi(self, EditFwRulesDlg):
+        EditFwRulesDlg.setWindowTitle(QtGui.QApplication.translate("EditFwRulesDlg", "Edit Firewall Rules", None, QtGui.QApplication.UnicodeUTF8))
+        self.newRuleButton.setText(QtGui.QApplication.translate("EditFwRulesDlg", "&New", None, QtGui.QApplication.UnicodeUTF8))
+        self.editRuleButton.setText(QtGui.QApplication.translate("EditFwRulesDlg", "&Edit", None, QtGui.QApplication.UnicodeUTF8))
+        self.deleteRuleButton.setText(QtGui.QApplication.translate("EditFwRulesDlg", "&Delete", None, QtGui.QApplication.UnicodeUTF8))
+

+ 88 - 0
qubesmanager/ui_newfwruledlg.py

@@ -0,0 +1,88 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'newfwruledlg.ui'
+#
+# Created: Wed Feb 16 20:55:59 2011
+#      by: PyQt4 UI code generator 4.7.3
+#
+# WARNING! All changes made in this file will be lost!
+
+from PyQt4 import QtCore, QtGui
+
+class Ui_NewFwRuleDlg(object):
+    def setupUi(self, NewFwRuleDlg):
+        NewFwRuleDlg.setObjectName("NewFwRuleDlg")
+        NewFwRuleDlg.setWindowModality(QtCore.Qt.NonModal)
+        NewFwRuleDlg.resize(311, 202)
+        NewFwRuleDlg.setModal(True)
+        self.buttonBox = QtGui.QDialogButtonBox(NewFwRuleDlg)
+        self.buttonBox.setGeometry(QtCore.QRect(30, 160, 271, 32))
+        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
+        self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
+        self.buttonBox.setObjectName("buttonBox")
+        self.label = QtGui.QLabel(NewFwRuleDlg)
+        self.label.setGeometry(QtCore.QRect(10, 10, 62, 17))
+        self.label.setObjectName("label")
+        self.groupBox = QtGui.QGroupBox(NewFwRuleDlg)
+        self.groupBox.setGeometry(QtCore.QRect(10, 40, 291, 121))
+        self.groupBox.setTitle("")
+        self.groupBox.setObjectName("groupBox")
+        self.label_2 = QtGui.QLabel(self.groupBox)
+        self.label_2.setGeometry(QtCore.QRect(10, 10, 62, 17))
+        self.label_2.setObjectName("label_2")
+        self.label_3 = QtGui.QLabel(self.groupBox)
+        self.label_3.setGeometry(QtCore.QRect(190, 10, 62, 17))
+        self.label_3.setObjectName("label_3")
+        self.allowCheckBox = QtGui.QCheckBox(self.groupBox)
+        self.allowCheckBox.setGeometry(QtCore.QRect(200, 80, 71, 23))
+        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.allowCheckBox.sizePolicy().hasHeightForWidth())
+        self.allowCheckBox.setSizePolicy(sizePolicy)
+        self.allowCheckBox.setObjectName("allowCheckBox")
+        self.addressEdit = QtGui.QLineEdit(self.groupBox)
+        self.addressEdit.setGeometry(QtCore.QRect(10, 30, 171, 27))
+        self.addressEdit.setObjectName("addressEdit")
+        self.label_4 = QtGui.QLabel(self.groupBox)
+        self.label_4.setGeometry(QtCore.QRect(10, 62, 31, 21))
+        self.label_4.setObjectName("label_4")
+        self.label_5 = QtGui.QLabel(self.groupBox)
+        self.label_5.setGeometry(QtCore.QRect(123, 62, 16, 21))
+        self.label_5.setObjectName("label_5")
+        self.netmaskComboBox = QtGui.QComboBox(self.groupBox)
+        self.netmaskComboBox.setGeometry(QtCore.QRect(190, 30, 84, 27))
+        self.netmaskComboBox.setObjectName("netmaskComboBox")
+        self.portBeginSpinBox = QtGui.QSpinBox(self.groupBox)
+        self.portBeginSpinBox.setGeometry(QtCore.QRect(50, 60, 71, 27))
+        self.portBeginSpinBox.setMaximum(65535)
+        self.portBeginSpinBox.setProperty("value", 0)
+        self.portBeginSpinBox.setObjectName("portBeginSpinBox")
+        self.portEndSpinBox = QtGui.QSpinBox(self.groupBox)
+        self.portEndSpinBox.setGeometry(QtCore.QRect(130, 60, 71, 27))
+        self.portEndSpinBox.setMaximum(65535)
+        self.portEndSpinBox.setObjectName("portEndSpinBox")
+        self.nameEdit = QtGui.QLineEdit(NewFwRuleDlg)
+        self.nameEdit.setGeometry(QtCore.QRect(60, 4, 241, 27))
+        self.nameEdit.setObjectName("nameEdit")
+
+        self.retranslateUi(NewFwRuleDlg)
+        QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("accepted()"), NewFwRuleDlg.accept)
+        QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), NewFwRuleDlg.reject)
+        QtCore.QMetaObject.connectSlotsByName(NewFwRuleDlg)
+        NewFwRuleDlg.setTabOrder(self.nameEdit, self.addressEdit)
+        NewFwRuleDlg.setTabOrder(self.addressEdit, self.netmaskComboBox)
+        NewFwRuleDlg.setTabOrder(self.netmaskComboBox, self.portBeginSpinBox)
+        NewFwRuleDlg.setTabOrder(self.portBeginSpinBox, self.portEndSpinBox)
+        NewFwRuleDlg.setTabOrder(self.portEndSpinBox, self.allowCheckBox)
+        NewFwRuleDlg.setTabOrder(self.allowCheckBox, self.buttonBox)
+
+    def retranslateUi(self, NewFwRuleDlg):
+        NewFwRuleDlg.setWindowTitle(QtGui.QApplication.translate("NewFwRuleDlg", "New Firewall Rule", None, QtGui.QApplication.UnicodeUTF8))
+        self.label.setText(QtGui.QApplication.translate("NewFwRuleDlg", "Name", None, QtGui.QApplication.UnicodeUTF8))
+        self.label_2.setText(QtGui.QApplication.translate("NewFwRuleDlg", "Address", None, QtGui.QApplication.UnicodeUTF8))
+        self.label_3.setText(QtGui.QApplication.translate("NewFwRuleDlg", "Netmask", None, QtGui.QApplication.UnicodeUTF8))
+        self.allowCheckBox.setText(QtGui.QApplication.translate("NewFwRuleDlg", "Allow", None, QtGui.QApplication.UnicodeUTF8))
+        self.label_4.setText(QtGui.QApplication.translate("NewFwRuleDlg", "Port", None, QtGui.QApplication.UnicodeUTF8))
+        self.label_5.setText(QtGui.QApplication.translate("NewFwRuleDlg", "-", None, QtGui.QApplication.UnicodeUTF8))
+