def checkConsistency(self, loader_context=None): # Import InterfaceResource and FirewallResource here instead of the top # of the file to avoid an import loop from ufwi_ruleset.forward.resource.interface import InterfaceResource from ufwi_ruleset.forward.resource.firewall import FirewallResource duplicates = set() for item in self.items: if isinstance(item.network, InterfaceResource): raise RulesetError( tr("You can not use an interface (%s) in a platform (%s)."), item.network.formatID(), self.formatID()) if isinstance(item.network, FirewallResource): raise RulesetError( tr("You can not use the firewall object in a platform (%s)."), self.formatID()) if item.network.interface != self.interface: raise RulesetError( tr('A platform (%s) can not contain network objects ' 'from different interfaces (%s and %s).'), self.formatID(), self.interface.formatID(), item.network.interface.formatID()) key = (item.network.id, item.protocol.id) if key in duplicates: raise RulesetError( tr("Duplicate item in the platform %s: (%s, %s)."), self.formatID(), item.network.formatID(), item.protocol.formatID()) duplicates.add(key)
def checkIdentifier(id): if not isinstance(id, unicode): raise RulesetError(tr("Invalid identifier: type is not unicode (%s)"), unicode(type(id))) if not id: raise RulesetError(tr("Invalid identifier: empty string")) if not REGEX_ID.match(id): raise RulesetError(tr("Invalid identifier: invalid characters or length (%s)"), repr(id))
def sendMailToAdmin_cb(self, unused, template_variables): template_variables['my_fqdn'] = '%s.%s' % ( template_variables['my_hostname'], template_variables['my_domain']) jinja_env = jinja.Environment() template = jinja_env.from_string(self.body_template) rendered_body = unicode(template.render(**template_variables)) msg = MIMEText(rendered_body.encode('utf-8'), 'plain', 'utf-8') msg['Subject'] = u'[EW4 %s] %s' % ( template_variables['my_hostname'], unicode(template_variables['subject'])) sender = self.config.sender_mail if check_mail(sender): msg['From'] = sender else: raise NuConfError(CONTACT_INVALID_SENDER, tr("'sender' e-mail : invalid e-mail address")) recipient = self.config.admin_mail if check_mail(recipient): msg['To'] = recipient else: raise NuConfError(CONTACT_INVALID_RECIPIENT, tr("'recipient' e-mail : invalid e-mail address")) defer = sendmail('127.0.0.1', sender, recipient, msg.as_string()) defer.addCallback(self.logSuccess) return defer
def loadFile(self, ruleset_context, filetype, name, editable=False, from_template=None, action=None, ruleset_id=0, filename=None, content=None): # Log the action logger = ruleset_context.logger text = "Load %s: %s" % (filetype, name) if ruleset_id == 0: logger.info(text) else: logger.debug(text) if not content: # Get the filename if not filename: if filetype == "library": filename = LIBRARY_FILENAME else: filename = rulesetFilename(filetype, name) # Parse the XML file try: with open(filename) as fp: ruleset = etree.parse(fp).getroot() except IOError, err: if err.errno == ENOENT: if filetype == 'template': message = tr('The "%s" template does not exist. It has been deleted or renamed.') else: message = tr('The "%s" rule set does not exist. It has been deleted or renamed.') raise RulesetError(message, name) else: raise RulesetError( tr('Unable to open file "%s" (%s): %s'), basename(filename), filetype, exceptionAsUnicode(err))
def moveAcl(self, acl, new_order, check_editable): # Compute rules order rules = self.acls old_order = self.getOrder(acl) length = len(rules) # Consistency checks if not (0 <= new_order < length): if new_order < old_order: format = tr("Unable to move up the %s: the rule is already the first of the %s chain.") else: format = tr("Unable to move down the %s: the rule is already the last of the %s chain.") raise RulesetError( format, unicode(acl), unicode(self)) if old_order < new_order: first = old_order last = new_order else: first = new_order last = old_order for order in xrange(first, last+1): print("check", order) check_editable(rules[order]) # Move the rule rule = rules.pop(old_order) rules.insert(new_order, rule)
def iptablesSave(logger, ipv6): """ Save current iptables rules into a file. Return the filename of the saved rules. Raise an IptablesError on error. """ if ipv6: filename = 'old_rules_ipv6' address_type = "IPv6" else: filename = 'old_rules_ipv4' address_type = "IPv4" filename = path_join(RULESET_DIR, filename) logger.warning("Save %s iptables rules to %s" % (address_type, filename)) if ipv6: command_str = IP6TABLES_SAVE else: command_str = IPTABLES_SAVE command = (command_str,) with open(filename, 'w') as rules: process, code = runCommandAsRoot(logger, command, timeout=22.5, stdout=rules) if code != 0: raise IptablesError(tr("%s command exited with code %s!"), command_str, code) size = getsize(filename) if not size: raise IptablesError(tr("%s command output is empty!"), command_str) return filename
def create(self, conf, logger): dbtype = conf['dbtype'] try: db_object = self.objects[dbtype] if isinstance(db_object, (str, unicode)): raise DatabaseError(tr('Unable to use %s: %s'), dbtype, toUnicode(db_object)) except KeyError, e: raise DatabaseError(tr('Unsupported database type %s'), dbtype)
def checkConsistency(self, loader_context=None): if self.day_to < self.day_from: raise RulesetError( tr("Invalid day range: %s..%s"), self.day_from, self.day_to) if self.hour_to <= self.hour_from: raise RulesetError( tr("Invalid hour range: %sh00..%sh59"), self.hour_from, (self.hour_to - 1))
def templatize(self, object, fusion): object.checkEditable() if object.isGeneric(): raise RulesetError(tr("The %s object is already a generic object."), object.formatID()) if not self.ruleset.is_template: raise RulesetError(tr("The rule set is not a template!")) attr = object.getAttributes() object.templatize(attr) return self.modifyObject(object, attr, fusion)
def _createTemplate(self, name, parent): if (name in self.include_templates) \ or (self.is_template and (self.name == name)): raise RulesetError( tr('The "%s" template can not be included twice'), name) identifier = 1 + len(self.include_templates) if 9 < identifier: raise RulesetError(tr("A rule set cannot comprise more than 9 templates!")) return IncludeTemplate(name, parent, identifier)
def getUserGroupNumber(group): try: group = int(group) except ValueError: raise RulesetError( tr("Invalid user group: %s"), unicode(group)) if not(MIN_GROUP <= group <= MAX_GROUP): raise RulesetError(tr("Invalid user group number: %s"), group) return group
def loadError(self, err, when): message = u"[%s] %s" % (err.__class__.__name__, exceptionAsUnicode(err)) if self.name: err = RulesetError( tr('Error while loading %s from the "%s" rule set: %s'), when, self.name, message) else: err = RulesetError( tr('Error on new rule set creation (while loading %s): %s'), when, message) reraise(err)
def _checkUserGroup(self, require_group_name, user_group): if require_group_name: if user_group.name is None: raise RulesetError( tr('The firewall uses user group names, but the %s user group has no name'), user_group.formatID()) else: if user_group.group is None: raise RulesetError( tr('The firewall uses user group numbers, but the %s user group has no number'), user_group.formatID())
def should_run(self, responsible): if not self.openvpn_cfg.enabled: if responsible: responsible.feedback(tr("Explicitely disabled.")) return False if not self.openvpn_cfg.client_network: if responsible: responsible.feedback( tr("No client network was defined, disabling server.") ) return False return True
def rulesetDelete(core, filetype, name): """ Delete the specified ruleset. """ if (filetype == "template") and (core.getMultisiteType() == MULTISITE_SLAVE): raise RulesetError(tr("Can not delete a template from a slave.")) filename = rulesetFilename(filetype, name) try: unlink(filename) except IOError, err: raise RulesetError(tr("Unable to delete the file %s (%s): %s!"), name, filetype, exceptionAsUnicode(err))
def _match(self, rule, attributes, match_func): if not attributes: raise RulesetError(tr("Empty attribute list")) for attr in attributes: if attr not in self.MATCH_ATTRIBUTES: raise RulesetError(tr("Unknown rule attribute: %s"), attr) # TODO platform use flattenNetworkList objects_a = getattr(self, attr) objects_b = getattr(rule, attr) if not match_func(objects_a, objects_b): return False return True
def build(self, request, filters): protos = {'tcp': 6, 'udp': 17, 'icmp': 1, 'igmp': 2} try: proto = protos[self.value] return '%s = %s' % ('ip_protocol', proto) except KeyError: raise RpcdError(tr('Protocol must be tcp or udp (is %s)'), self.value) raise RpcdError(tr('Unknown protocol: %s'), self.value)
def create(self, context, data): "Create an anonymous session" client_name = getUnicode("client_name", data['client_name'], 3, 100) protocol_version = getUnicode("protocol_version", data['protocol_version'], 3, 100) # Check client name and protocol version if not client_name or not (3 <= len(client_name) <= 20): raise SessionError(SESSION_INVALID_ARG, tr("Invalid client name: need a string with length in 3..20")) if not protocol_version or not (3 <= len(protocol_version) <= 10): raise SessionError(SESSION_INVALID_ARG, tr("Invalid protocol version: need a string with length in 3..10")) # Check protocol version if protocol_version != PROTOCOL_VERSION: raise SessionError(SESSION_INVALID_VERSION, tr("Invalid protocol version: %s"), repr(protocol_version)) # Only a user with no session can create a new session if not context.user: raise SessionError(SESSION_NO_USER, tr("Only a user can create a session!")) if context.hasSession(): raise SessionError(SESSION_DUPLICATE, tr("You already own a session!")) # Fill the user context user = context.user if 'client_release' in data: #size between 3 and 100 user.client_release = getUnicode('client_release', data['client_release'], 3, 100) user.groups = ["anonymous"] user.client_name = client_name user.protocol_version = protocol_version # Create the session cookie = self.createCookie() filename = b32encode(cookie).strip("=") + ".pickle" filename = path_join(self.path, filename) cookie = b64encode(cookie) session = Session(cookie, filename, user) # Register the session and write it to the disk self.sessions[session.cookie] = session context.setSession(session) session.save() # Session created return session.cookie
def checkServiceCall(self, context, service_name): ruleset_open = self.hasRules(context) if service_name == "open": if ruleset_open: rules = self.getRulesFile(context) raise LocalFWError( tr("There is already an active rule set (%s)."), rules.name) else: if not ruleset_open: raise LocalFWError( tr("You have to open a rule set to use the %s() service."), service_name)
def taskDone(self, ret): if isinstance(ret, Failure): self.setError(ret.getErrorMessage()) self.fw.error( tr("Error while performing task on firewall %s: %s") % (self.fw.name, str(ret.getErrorMessage())) ) self.fw.debug( tr("Error while applying updates to firewall %s: %s") % (self.fw.name, str(ret.getTraceback())) ) return if self.task_stop_on_success: self.state = FINNISHED self.task.stop()
def service_getCertificatesInfo(self, ctx): """ Return information about certifiates/eky currently set, in the form of a dictionnary: { 'cert' : ['brief description', 'certificate content'], 'key' : ['md5 of the key', ''], 'ca' : ['brief description', 'CA content'], 'crl' : ['brief description', 'CRL content'], } """ infos = { 'cert' : [tr('No certificate set'), tr('No certificate has been set yet')], 'key' : [tr('No key set'), ''], 'ca' : [tr('No CA is set'), tr('No certificate authority has been set yet')], 'crl' : [tr('No CRL set'), tr('No certificate revocation list has been set yet')], } # Certificate try: if isfile(self.CERT_PATH): cert = load_cert(self.CERT_PATH) infos['cert'][0] = unicode(cert.get_subject()) infos['cert'][1] = unicode(cert.as_text()) except Exception, error: infos['cert'][0] = tr('Invalid certificate') self.cert_logger.debug("Invalid cert : %s" % error)
def checkRule(self, apply_rules, recursive=False): if not Rule.checkRule(self, apply_rules, recursive=recursive): return False if self.isForward() and (not self.config.isGateway()): apply_rules.error( tr("The firewall is configured as a local firewall: " "%s can not be generated."), unicode(self)) return False if self.user_groups and (not self.ruleset.useNuFW()): apply_rules.warning( tr("Identity-based Firewall is disabled: %s will not use identity."), unicode(self)) return True
def checkXMLroot(self, root): if root.tag != CONFIG_ROOT_TAG: raise ConfigError(CONFIG_ERR_XML_READ, tr('XML root is not %s'), CONFIG_ROOT_TAG) for item in root.items(): if item[0] == VERSION_ATTR: if item[1] == VERSION: return else: raise ConfigError(CONFIG_ERR_XML_READ, tr('VariablesStore version expected: %s, got %s'), VERSION, item[1]) raise ConfigError(CONFIG_ERR_XML_READ, tr('VariablesStore version not found (expected version="%s")'), VERSION)
def delete(self, identifier): # FIXME: Factorize into Library.delete() # Get the resource resource = self.resources[identifier] resource.checkEditable() # Get all references resources = [resource] + resource.getChildren(recursive=True) for resource in resources: if not resource.references: continue # FIXME: avoid unicode(object) references = ", ".join(unicode(ref) for ref in resource.references) raise RulesetError(tr('Unable to delete the "%s" network: it is used by %s!'), resource.id, references) # Create the action identifiers = [resource.id for resource in resources] apply_updates = Update(u"resources", "delete", *identifiers) unapply_updates = Update(u"resources", "create", *identifiers) action = Action( ActionHandler(apply_updates, self._deleteMany, resources), ActionHandler(unapply_updates, self._createMany, resources), ) # Apply the action return self.ruleset.addAction(action)
def rulesetUpload(component, logger, filetype, input_filename, content, netcfg): # Extract ruleset name from the input filename name = basename(input_filename) if not name.lower().endswith(".xml"): raise RulesetError('File extension is not ".xml"!') name = name[:-4] # Ensure that the ruleset doesn't exist on disk rulesetFilename(filetype, name, check_existing=True) # Decode the content content = decodeFileContent(content) # Open the ruleset the check the consistency ruleset = Ruleset(component, logger, netcfg, read_only=True) ruleset.load(logger, filetype, name, content=content) if component.core.getMultisiteType() == MULTISITE_SLAVE: if exists(MULTISITE_TEMPLATE_FILENAME): template = MULTISITE_TEMPLATE_NAME else: template = None replaceTemplate(logger, ruleset, template) # Write the ruleset try: ruleset.save() except IOError, err: raise RulesetError( tr("Unable to write into the file %s (%s): %s!"), basename(ruleset.filename), ruleset.filetype, exceptionAsUnicode(err), )
def rulesetDownload(filetype, name): filename = rulesetFilename(filetype, name) try: with open(filename, "rb") as fp: content = fp.read() except IOError, err: raise RulesetError(tr('Unable to open "%s" (%s): %s!'), basename(filename), filetype, exceptionAsUnicode(err))
def init(self, data, loader_context=None, is_modify=True): """ Write the attribute values and check object consistency. The operation is atomic: restore old attributes on error. """ previous_state = dict(self.__dict__) if is_modify: old_attr = self.getAttributes() try: data = dict(data) self.setAttributes(data, is_modify) keys = data.keys() if keys: raise RulesetError( tr("Unknown attributes: %s"), u', '.join(keys)) if loader_context: self.onLoading(loader_context) if is_modify: self.onModify(old_attr) self.checkConsistency(loader_context) if is_modify: for reference in self.references: reference.checkConsistency(loader_context) except: # Restore previous (valid) state on error self.__dict__ = previous_state raise
def removeTemplate(self, name): template = self.include_templates[name] if template.parent: raise RulesetError( tr('It is not possible to delete the "%s" template, included in the "%s" template'), name, template.parent) templates = [template] for template in self.include_templates.itervalues(): if template.parent != name: continue templates.append(template) names = [template.name for template in templates] updates = Updates(Update("ruleset", "update", -1)) action = Action( ActionHandler(updates, self._removeTemplates, names), ActionHandler(updates, self._addTemplates, templates)) action.apply() try: for library in self._libraries.itervalues(): library.removeTemplate(action, name) except: # Rollback action.unapply() raise return self.addAction(action, apply=False)
def sysctlSet(logger, key, value): command = [SYSCTL, u"-n", u"-q", u"-w", u"%s=%s" % (key, value)] process, code = runCommandAsRoot(logger, command) if code != 0: raise RulesetError( tr("sysctl error: unable to set %s value to %s! (exit code %s)"), key, value, code)
def ldapRules(context, component, ruleset, rule_type, identifiers): logger = ContextLoggerChild(context, component) result = ApplyRulesResult(logger) if rule_type == 'acls-ipv6': rules = ruleset.acls_ipv6 elif rule_type == 'acls-ipv4': rules = ruleset.acls_ipv4 else: # NuFW (LDAP) doesn't authenticate NAT rules raise RulesetError(tr("LDAP doesn't support rule type: %s"), repr(rule_type)) if identifiers: rules = [ rules[id] for id in identifiers ] else: rules = rules ldap = WriteLdapRules(logger, component.config['ldap']) with TemplateInstanciation(ruleset): rules = filterRules(result, rules) lines = [] for dn, attr in ldap.createRules(rules): lines.append(unicode(dn)) attrs = attr.items() attrs.sort(key=lambda item: item[0]) for key, value in attrs: lines.append(u" %s=%r" % (key, value)) lines.append(u"") xmlrpc = result.exportXMLRPC() xmlrpc['ldap'] = lines return xmlrpc