def _read_rules(self): """Read in rules that were added by ufw.""" rfns = [self.files["rules"]] if self.use_ipv6(): rfns.append(self.files["rules6"]) for f in rfns: try: orig = ufw.util.open_file_read(f) except Exception: err_msg = _("Couldn't open '%s' for reading") % (f) raise UFWError(err_msg) pat_tuple = re.compile(r"^### tuple ###\s*") for line in orig: if pat_tuple.match(line): tupl = pat_tuple.sub("", line) tmp = re.split(r"\s+", tupl.strip()) if len(tmp) < 6 or len(tmp) > 9: warn_msg = _("Skipping malformed tuple (bad length): %s") % (tupl) warn(warn_msg) continue else: # set direction to "in" to support upgrades # from old format, which only had 6 or 8 fields type = "in" interface = "" if len(tmp) == 7 or len(tmp) == 9: if "_" in tmp[-1]: (type, interface) = tmp[-1].split("_") else: type = tmp[-1] try: if len(tmp) < 8: rule = UFWRule(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], type) else: rule = UFWRule(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], type) # Removed leading [sd]app_ and unescape spaces pat_space = re.compile("%20") if tmp[6] != "-": rule.dapp = pat_space.sub(" ", tmp[6]) if tmp[7] != "-": rule.sapp = pat_space.sub(" ", tmp[7]) if interface != "": rule.set_interface(type, interface) except UFWError: warn_msg = _("Skipping malformed tuple: %s") % (tupl) warn(warn_msg) continue if f == self.files["rules6"]: rule.set_v6(True) self.rules6.append(rule) else: rule.set_v6(False) self.rules.append(rule) orig.close()
def reset(self): '''Reset the firewall''' res = "" # First make sure we have all the original files allfiles = [] for i in self.files: if not self.files[i].endswith('.rules'): continue allfiles.append(self.files[i]) fn = os.path.join(ufw.common.share_dir, "iptables", \ os.path.basename(self.files[i])) if not os.path.isfile(fn): err_msg = _("Could not find '%s'. Aborting") % (fn) raise UFWError(err_msg) ext = time.strftime("%Y%m%d_%H%M%S") # This implementation will intentionally traceback if someone tries to # do something to take advantage of the race conditions here. # Don't do anything if the files already exist for i in allfiles: fn = "%s.%s" % (i, ext) if os.path.exists(fn): err_msg = _("'%s' already exists. Aborting") % (fn) raise UFWError(err_msg) # Move the old to the new for i in allfiles: fn = "%s.%s" % (i, ext) res += _("Backing up '%(old)s' to '%(new)s'\n") % (\ {'old': os.path.basename(i), 'new': fn}) os.rename(i, fn) # Copy files into place for i in allfiles: old = "%s.%s" % (i, ext) shutil.copy(os.path.join(ufw.common.share_dir, "iptables", \ os.path.basename(i)), \ os.path.dirname(i)) shutil.copymode(old, i) try: statinfo = os.stat(i) mode = statinfo[stat.ST_MODE] except Exception: warn_msg = _("Couldn't stat '%s'") % (i) warn(warn_msg) continue if mode & stat.S_IWOTH: res += _("WARN: '%s' is world writable") % (i) elif mode & stat.S_IROTH: res += _("WARN: '%s' is world readable") % (i) return res
def initcaps(self): '''Initialize the capabilities database. This needs to be called before accessing the database.''' # Only initialize if not initialized already if self.caps is not None: return self.caps = {} self.caps['limit'] = {} # Set defaults for dryrun, non-root, etc self.caps['limit']['4'] = True self.caps['limit']['6'] = False # historical default for the testsuite # Try to get capabilities from the running system if root if self.do_checks and os.getuid( ) == 0 and not self.dryrun: # pragma: no coverage # v4 try: nf_caps = ufw.util.get_netfilter_capabilities(self.iptables) except OSError as e: msg = "initcaps\n%s" % e if self.is_enabled(): error(msg) warn(msg) return if 'recent-set' in nf_caps and 'recent-update' in nf_caps: self.caps['limit']['4'] = True else: self.caps['limit']['4'] = False # v6 (skip capabilities check for ipv6 if ipv6 is disabled in ufw # because the system may not have ipv6 support (LP: #1039729) if self.use_ipv6(): try: nf_caps = ufw.util.get_netfilter_capabilities( self.ip6tables) except OSError as e: error("initcaps\n%s" % e) if 'recent-set' in nf_caps and 'recent-update' in nf_caps: self.caps['limit']['6'] = True else: self.caps['limit']['6'] = False
def set_rule(self, rule, ip_version): '''Updates firewall with rule''' res = "" err_msg = "" tmp = "" rules = [] if rule.dapp == "" and rule.sapp == "": rules.append(rule) else: tmprules = [] try: if rule.remove: if ip_version == "v4": tmprules = self.backend.get_app_rules_from_system( rule, False) elif ip_version == "v6": tmprules = self.backend.get_app_rules_from_system( rule, True) elif ip_version == "both": tmprules = self.backend.get_app_rules_from_system( rule, False) tmprules6 = self.backend.get_app_rules_from_system( rule, True) # Only add rules that are different by more than v6 (we # will handle 'ip_version == both' specially, below). for x in tmprules: for y in tmprules6: prev6 = y.v6 y.v6 = False if not x.match(y): y.v6 = prev6 tmprules.append(y) else: err_msg = _("Invalid IP version '%s'") % (ip_version) raise UFWError(err_msg) # Don't process removal of non-existing application rules if len(tmprules) == 0 and not self.backend.dryrun: tmp = _("Could not delete non-existent rule") if ip_version == "v4": res = tmp elif ip_version == "v6": res = tmp + " (v6)" elif ip_version == "both": res = tmp + "\n" + tmp + " (v6)" return res for tmp in tmprules: r = tmp.dup_rule() r.remove = rule.remove r.set_action(rule.action) r.set_logtype(rule.logtype) rules.append(r) else: rules = self.backend.get_app_rules_from_template(rule) # Reverse the order of rules for inserted rules, so they # are inserted in the right order if rule.position > 0: rules.reverse() except Exception: raise count = 0 set_error = False pos_err_msg = _("Invalid position '") num_v4 = self.backend.get_rules_count(False) num_v6 = self.backend.get_rules_count(True) for i, r in enumerate(rules): count = i if r.position > num_v4 + num_v6: pos_err_msg += str(r.position) + "'" raise UFWError(pos_err_msg) try: if self.backend.use_ipv6(): if ip_version == "v4": if r.position > num_v4: pos_err_msg += str(r.position) + "'" raise UFWError(pos_err_msg) r.set_v6(False) tmp = self.backend.set_rule(r) elif ip_version == "v6": if r.position > num_v4: r.set_position(r.position - num_v4) elif r.position != 0 and r.position <= num_v4: pos_err_msg += str(r.position) + "'" raise UFWError(pos_err_msg) r.set_v6(True) tmp = self.backend.set_rule(r) elif ip_version == "both": user_pos = r.position # user specified position r.set_v6(False) if not r.remove and user_pos > num_v4: # The user specified a v6 rule, so try to find a # match in the v4 rules and use its position. p = self.backend.find_other_position( \ user_pos - num_v4 + count, True) if p > 0: r.set_position(p) else: # If not found, then add the rule r.set_position(0) tmp = self.backend.set_rule(r) # We need to readjust the position since the number # the number of ipv4 rules increased if not r.remove and user_pos > 0: num_v4 = self.backend.get_rules_count(False) r.set_position(user_pos + 1) r.set_v6(True) if not r.remove and r.position > 0 and \ r.position <= num_v4: # The user specified a v4 rule, so try to find a # match in the v6 rules and use its position. p = self.backend.find_other_position(r.position, \ False) if p > 0: # Subtract count since the list is reversed r.set_position(p - count) else: # If not found, then add the rule r.set_position(0) if tmp != "": tmp += "\n" # Readjust position to send to set_rule if not r.remove and r.position > num_v4: r.set_position(r.position - num_v4) tmp += self.backend.set_rule(r) else: err_msg = _("Invalid IP version '%s'") % (ip_version) raise UFWError(err_msg) else: if ip_version == "v4" or ip_version == "both": r.set_v6(False) tmp = self.backend.set_rule(r) elif ip_version == "v6": err_msg = _("IPv6 support not enabled") raise UFWError(err_msg) else: err_msg = _("Invalid IP version '%s'") % (ip_version) raise UFWError(err_msg) except UFWError as e: err_msg = e.value set_error = True break if r.updated: warn_msg = _("Rule changed after normalization") warnings.warn(warn_msg) if not set_error: # Just return the last result if no error res += tmp elif len(rules) == 1: # If no error, and just one rule, error out error(err_msg) # pragma: no cover else: # If error and more than one rule, delete the successfully added # rules in reverse order undo_error = False indexes = list(range(count + 1)) indexes.reverse() for j in indexes: if count > 0 and rules[j]: backout_rule = rules[j].dup_rule() backout_rule.remove = True try: self.set_rule(backout_rule, ip_version) except Exception: # Don't fail, so we can try to backout more undo_error = True warn_msg = _("Could not back out rule '%s'") % \ r.format_rule() warn(warn_msg) err_msg += _("\nError applying application rules.") if undo_error: err_msg += _(" Some rules could not be unapplied.") else: err_msg += _(" Attempted rules successfully unapplied.") raise UFWError(err_msg) return res
def get_profiles(profiles_dir): '''Get profiles found in profiles database. Returns dictionary with profile name as key and tuples for fields ''' if not os.path.isdir(profiles_dir): err_msg = _("Profiles directory does not exist") raise UFWError(err_msg) max_size = 10 * 1024 * 1024 # 10MB profiles = {} files = os.listdir(profiles_dir) files.sort() total_size = 0 pat = re.compile(r'^\.') for f in files: abs_path = profiles_dir + "/" + f if not os.path.isfile(abs_path): continue if pat.search(f): debug("Skipping '%s': hidden file" % (f)) continue if f.endswith('.dpkg-new') or f.endswith('.dpkg-old') or \ f.endswith('.dpkg-dist') or f.endswith('.rpmnew') or \ f.endswith('.rpmsave') or f.endswith('~'): debug("Skipping '%s'" % (f)) continue # Try to gracefully handle huge files for the user (no security # benefit, just usability) size = 0 try: size = os.stat(abs_path)[stat.ST_SIZE] except Exception: warn_msg = _("Skipping '%s': couldn't stat") % (f) warn(warn_msg) continue if size > max_size: warn_msg = _("Skipping '%s': too big") % (f) warn(warn_msg) continue if total_size + size > max_size: warn_msg = _("Skipping '%s': too many files read already") % (f) warn(warn_msg) continue total_size += size if sys.version_info[0] < 3: cdict = ConfigParser.RawConfigParser() else: cdict = configparser.RawConfigParser() try: cdict.read(abs_path) except Exception: warn_msg = _("Skipping '%s': couldn't process") % (f) warn(warn_msg) continue # If multiple occurences of profile name, use the last one for p in cdict.sections(): if len(p) > 64: warn_msg = _("Skipping '%s': name too long") % (p) warn(warn_msg) continue if not valid_profile_name(p): warn_msg = _("Skipping '%s': invalid name") % (p) warn(warn_msg) continue try: ufw.util.get_services_proto(p) warn_msg = _("Skipping '%s': also in /etc/services") % (p) warn(warn_msg) continue except Exception: pass skip = False for key, value in cdict.items(p): if len(key) > 64: warn_msg = _("Skipping '%s': field too long") % (p) warn(warn_msg) skip = True break if len(value) > 1024: warn_msg = _("Skipping '%(value)s': value too long for " \ "'%(field)s'") % \ ({'value': p, 'field': key}) warn(warn_msg) skip = True break if skip: continue if p in profiles: warn_msg = _("Duplicate profile '%s', using last found") % (p) warn(warn_msg) pdict = {} for key, value in cdict.items(p): #debug("add '%s' = '%s' to '%s'" % (key, value, p)) pdict[key] = value profiles[p] = pdict return profiles
def _do_checks(self): '''Perform basic security checks: is setuid or setgid (for non-Linux systems) checks that script is owned by root checks that every component in absolute path are owned by root warn if script is group writable warn if part of script path is group writable Doing this at the beginning causes a race condition with later operations that don't do these checks. However, if the user running this script is root, then need to be root to exploit the race condition (and you are hosed anyway...) ''' if not self.do_checks: err_msg = _("Checks disabled") warn(err_msg) return True # Not needed on Linux, but who knows the places we will go... if os.getuid() != os.geteuid(): err_msg = _("ERROR: this script should not be SUID") raise UFWError(err_msg) if os.getgid() != os.getegid(): err_msg = _("ERROR: this script should not be SGID") raise UFWError(err_msg) uid = os.getuid() if uid != 0: err_msg = _("You need to be root to run this script") raise UFWError(err_msg) # Use these so we only warn once warned_world_write = {} warned_group_write = {} warned_owner = {} profiles = [] if not os.path.isdir(self.files['apps']): warn_msg = _("'%s' does not exist") % (self.files['apps']) warn(warn_msg) else: pat = re.compile(r'^\.') for profile in os.listdir(self.files['apps']): if not pat.search(profile): profiles.append(os.path.join(self.files['apps'], profile)) for path in self.files.values() + [ os.path.abspath(sys.argv[0]) ] + \ profiles: while True: debug("Checking " + path) if path == self.files['apps'] and \ not os.path.isdir(self.files['apps']): break try: statinfo = os.stat(path) mode = statinfo[ST_MODE] except OSError, e: err_msg = _("Couldn't stat '%s'") % (path) raise UFWError(err_msg) except Exception: raise if statinfo.st_uid != 0 and not warned_owner.has_key(path): warn_msg = _("uid is %(uid)s but '%(path)s' is owned by " \ "%(st_uid)s") % ({'uid': str(uid), \ 'path': path, \ 'st_uid': str(statinfo.st_uid)}) warn(warn_msg) warned_owner[path] = True if mode & S_IWOTH and not warned_world_write.has_key(path): warn_msg = _("%s is world writable!") % (path) warn(warn_msg) warned_world_write[path] = True if mode & S_IWGRP and not warned_group_write.has_key(path): warn_msg = _("%s is group writable!") % (path) warn(warn_msg) warned_group_write[path] = True if path == "/": break path = os.path.dirname(path) if not path: raise OSError(errno.ENOENT, "Could not find '%s'" % (path))
def get_profiles(profiles_dir): '''Get profiles found in profiles database. Returns dictionary with profile name as key and tuples for fields ''' if not os.path.isdir(profiles_dir): err_msg = _("Profiles directory does not exist") raise UFWError(err_msg) max_size = 10 * 1024 * 1024 # 10MB profiles = {} files = os.listdir(profiles_dir) files.sort() total_size = 0 pat = re.compile(r'^\.') for f in files: abs_path = profiles_dir + "/" + f if not os.path.isfile(abs_path): continue if pat.search(f): debug("Skipping '%s': hidden file" % (f)) continue if f.endswith('.dpkg-new') or f.endswith('.dpkg-old') or \ f.endswith('.dpkg-dist') or f.endswith('.rpmnew') or \ f.endswith('.rpmsave') or f.endswith('~'): debug("Skipping '%s'" % (f)) continue # Try to gracefully handle huge files for the user (no security # benefit, just usability) size = 0 try: size = os.stat(abs_path)[stat.ST_SIZE] except Exception: warn_msg = _("Skipping '%s': couldn't stat") % (f) warn(warn_msg) continue if size > max_size: warn_msg = _("Skipping '%s': too big") % (f) warn(warn_msg) continue if total_size + size > max_size: warn_msg = _("Skipping '%s': too many files read already") % (f) warn(warn_msg) continue total_size += size if sys.version_info[0] < 3: # pragma: no cover cdict = ConfigParser.RawConfigParser() else: # pragma: no cover cdict = configparser.RawConfigParser() try: cdict.read(abs_path) except Exception: warn_msg = _("Skipping '%s': couldn't process") % (f) warn(warn_msg) continue # If multiple occurences of profile name, use the last one for p in cdict.sections(): if len(p) > 64: warn_msg = _("Skipping '%s': name too long") % (p) warn(warn_msg) continue if not valid_profile_name(p): warn_msg = _("Skipping '%s': invalid name") % (p) warn(warn_msg) continue try: ufw.util.get_services_proto(p) warn_msg = _("Skipping '%s': also in /etc/services") % (p) warn(warn_msg) continue except Exception: pass skip = False for key, value in cdict.items(p): if len(key) > 64: warn_msg = _("Skipping '%s': field too long") % (p) warn(warn_msg) skip = True break if len(value) > 1024: warn_msg = _("Skipping '%(value)s': value too long for " \ "'%(field)s'") % \ ({'value': p, 'field': key}) warn(warn_msg) skip = True break if skip: continue if p in profiles: warn_msg = _("Duplicate profile '%s', using last found") % (p) warn(warn_msg) pdict = {} for key, value in cdict.items(p): #debug("add '%s' = '%s' to '%s'" % (key, value, p)) pdict[key] = value try: verify_profile(p, pdict) profiles[p] = pdict except UFWError as e: warn(e) return profiles
def set_rule(self, rule, ip_version): '''Updates firewall with rule''' res = "" err_msg = "" tmp = "" rules = [] if rule.dapp == "" and rule.sapp == "": rules.append(rule) else: tmprules = [] try: if rule.remove: if ip_version == "v4": tmprules = self.backend.get_app_rules_from_system( rule, False) elif ip_version == "v6": tmprules = self.backend.get_app_rules_from_system( rule, True) elif ip_version == "both": tmprules = self.backend.get_app_rules_from_system( rule, False) tmprules6 = self.backend.get_app_rules_from_system( rule, True) # Only add rules that are different by more than v6 (we # will handle 'ip_version == both' specially, below). for x in tmprules: for y in tmprules6: prev6 = y.v6 y.v6 = False if not x.match(y): y.v6 = prev6 tmprules.append(y) else: err_msg = _("Invalid IP version '%s'") % (ip_version) raise UFWError(err_msg) # Don't process removal of non-existing application rules if len(tmprules) == 0 and not self.backend.dryrun: tmp = _("Could not delete non-existent rule") if ip_version == "v4": res = tmp elif ip_version == "v6": res = tmp + " (v6)" elif ip_version == "both": res = tmp + "\n" + tmp + " (v6)" return res for tmp in tmprules: r = tmp.dup_rule() r.remove = rule.remove r.set_action(rule.action) r.set_logtype(rule.logtype) rules.append(r) else: rules = self.backend.get_app_rules_from_template(rule) # Reverse the order of rules for inserted rules, so they # are inserted in the right order if rule.position > 0: rules.reverse() except Exception: raise count = 0 set_error = False pos_err_msg = _("Invalid position '") num_v4 = self.backend.get_rules_count(False) num_v6 = self.backend.get_rules_count(True) for i, r in enumerate(rules): count = i if r.position > num_v4 + num_v6: pos_err_msg += str(r.position) + "'" raise UFWError(pos_err_msg) try: if self.backend.use_ipv6(): if ip_version == "v4": if r.position > num_v4: pos_err_msg += str(r.position) + "'" raise UFWError(pos_err_msg) r.set_v6(False) tmp = self.backend.set_rule(r) elif ip_version == "v6": if r.position > num_v4: r.set_position(r.position - num_v4) elif r.position != 0 and r.position <= num_v4: pos_err_msg += str(r.position) + "'" raise UFWError(pos_err_msg) r.set_v6(True) tmp = self.backend.set_rule(r) elif ip_version == "both": user_pos = r.position # user specified position r.set_v6(False) if not r.remove and user_pos > num_v4: # The user specified a v6 rule, so try to find a # match in the v4 rules and use its position. p = self.backend.find_other_position( \ user_pos - num_v4 + count, True) if p > 0: r.set_position(p) else: # If not found, then add the rule r.set_position(0) tmp = self.backend.set_rule(r) # We need to readjust the position since the number # the number of ipv4 rules increased if not r.remove and user_pos > 0: num_v4 = self.backend.get_rules_count(False) r.set_position(user_pos + 1) r.set_v6(True) if not r.remove and r.position > 0 and \ r.position <= num_v4: # The user specified a v4 rule, so try to find a # match in the v6 rules and use its position. p = self.backend.find_other_position(r.position, \ False) if p > 0: # Subtract count since the list is reversed r.set_position(p - count) else: # If not found, then add the rule r.set_position(0) if tmp != "": tmp += "\n" # Readjust position to send to set_rule if not r.remove and r.position > num_v4: r.set_position(r.position - num_v4) tmp += self.backend.set_rule(r) else: err_msg = _("Invalid IP version '%s'") % (ip_version) raise UFWError(err_msg) else: if ip_version == "v4" or ip_version == "both": r.set_v6(False) tmp = self.backend.set_rule(r) elif ip_version == "v6": err_msg = _("IPv6 support not enabled") raise UFWError(err_msg) else: err_msg = _("Invalid IP version '%s'") % (ip_version) raise UFWError(err_msg) except UFWError as e: err_msg = e.value set_error = True break if r.updated: warn_msg = _("Rule changed after normalization") warnings.warn(warn_msg) if not set_error: # Just return the last result if no error res += tmp elif len(rules) == 1: # If no error, and just one rule, error out error(err_msg) # pragma: no cover else: # If error and more than one rule, delete the successfully added # rules in reverse order undo_error = False indexes = list(range(count+1)) indexes.reverse() for j in indexes: if count > 0 and rules[j]: backout_rule = rules[j].dup_rule() backout_rule.remove = True try: self.set_rule(backout_rule, ip_version) except Exception: # Don't fail, so we can try to backout more undo_error = True warn_msg = _("Could not back out rule '%s'") % \ r.format_rule() warn(warn_msg) err_msg += _("\nError applying application rules.") if undo_error: err_msg += _(" Some rules could not be unapplied.") else: err_msg += _(" Attempted rules successfully unapplied.") raise UFWError(err_msg) return res
# rules in reverse order undo_error = False indexes = range(count+1) indexes.reverse() for j in indexes: if count > 0 and rules[j]: backout_rule = rules[j].dup_rule() backout_rule.remove = True try: self.set_rule(backout_rule, ip_version) except Exception: # Don't fail, so we can try to backout more undo_error = True warn_msg = _("Could not back out rule '%s'") % \ r.format_rule() warn(warn_msg) err_msg += _("\nError applying application rules.") if undo_error: err_msg += _(" Some rules could not be unapplied.") else: err_msg += _(" Attempted rules successfully unapplied.") raise UFWError(err_msg) return res def delete_rule(self, number, force=False): '''Delete rule''' try: n = int(number)
def _do_checks(self): # pragma: no coverage '''Perform basic security checks: is setuid or setgid (for non-Linux systems) checks that script is owned by root checks that every component in absolute path are owned by root warn if script is group writable warn if part of script path is group writable Doing this at the beginning causes a race condition with later operations that don't do these checks. However, if the user running this script is root, then need to be root to exploit the race condition (and you are hosed anyway...) ''' if not self.do_checks: err_msg = _("Checks disabled") warn(err_msg) return True # Not needed on Linux, but who knows the places we will go... if os.getuid() != os.geteuid(): err_msg = _("ERROR: this script should not be SUID") raise UFWError(err_msg) if os.getgid() != os.getegid(): err_msg = _("ERROR: this script should not be SGID") raise UFWError(err_msg) uid = os.getuid() if uid != 0: err_msg = _("You need to be root to run this script") raise UFWError(err_msg) # Use these so we only warn once warned_world_write = {} warned_group_write = {} warned_owner = {} profiles = [] if not os.path.isdir(self.files['apps']): warn_msg = _("'%s' does not exist") % (self.files['apps']) warn(warn_msg) else: pat = re.compile(r'^\.') for profile in os.listdir(self.files['apps']): if not pat.search(profile): profiles.append(os.path.join(self.files['apps'], profile)) for path in list(self.files.values()) + \ [ os.path.abspath(sys.argv[0]) ] + \ profiles: if not path.startswith('/'): path = "%s/%s" % (os.getcwd(), path) while True: debug("Checking " + path) if path == self.files['apps'] and \ not os.path.isdir(self.files['apps']): break try: statinfo = os.stat(path) mode = statinfo[stat.ST_MODE] except OSError: err_msg = _("Couldn't stat '%s'") % (path) raise UFWError(err_msg) except Exception: raise # snaps and clicks unpack to this, so handle it click_user = '******' snap_user = '******' is_unpack_user = False try: if pwd.getpwuid(statinfo.st_uid)[0] == click_user or \ pwd.getpwuid(statinfo.st_uid)[0] == snap_user: is_unpack_user = True except KeyError: pass if statinfo.st_uid != 0 and not is_unpack_user and \ path not in warned_owner: warn_msg = _("uid is %(uid)s but '%(path)s' is owned by " \ "%(st_uid)s") % ({'uid': str(uid), \ 'path': path, \ 'st_uid': str(statinfo.st_uid)}) warn(warn_msg) warned_owner[path] = True if mode & stat.S_IWOTH and path not in warned_world_write: warn_msg = _("%s is world writable!") % (path) warn(warn_msg) warned_world_write[path] = True if mode & stat.S_IWGRP and path not in warned_group_write and \ statinfo.st_gid != 0: warn_msg = _("%s is group writable!") % (path) warn(warn_msg) warned_group_write[path] = True if path == "/": break last_path = path path = os.path.dirname(path) if not path: raise OSError(errno.ENOENT, \ "Could not find parent for '%s'" % \ (last_path)) for f in self.files: if f != 'apps' and not os.path.isfile(self.files[f]): err_msg = _("'%(f)s' file '%(name)s' does not exist") % \ ({'f': f, 'name': self.files[f]}) raise UFWError(err_msg)
def _read_rules(self): '''Read in rules that were added by ufw''' rfns = [self.files['rules']] if self.use_ipv6(): rfns.append(self.files['rules6']) for f in rfns: try: orig = ufw.util.open_file_read(f) except Exception: err_msg = _("Couldn't open '%s' for reading") % (f) raise UFWError(err_msg) pat_tuple = re.compile(r'^### tuple ###\s*') for line in orig: if pat_tuple.match(line): tupl = pat_tuple.sub('', line) tmp = re.split(r'\s+', tupl.strip()) if len(tmp) < 6 or len(tmp) > 9: wmsg = _("Skipping malformed tuple (bad length): %s") \ % (tupl) warn(wmsg) continue else: # set direction to "in" to support upgrades # from old format, which only had 6 or 8 fields dtype = "in" interface = "" if len(tmp) == 7 or len(tmp) == 9: if '_' in tmp[-1]: (dtype, interface) = tmp[-1].split('_') else: dtype = tmp[-1] try: if len(tmp) < 8: rule = UFWRule(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], dtype) else: rule = UFWRule(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], dtype) # Removed leading [sd]app_ and unescape spaces pat_space = re.compile('%20') if tmp[6] != "-": rule.dapp = pat_space.sub(' ', tmp[6]) if tmp[7] != "-": rule.sapp = pat_space.sub(' ', tmp[7]) if interface != "": rule.set_interface(dtype, interface) except UFWError: warn_msg = _("Skipping malformed tuple: %s") % \ (tupl) warn(warn_msg) continue if f == self.files['rules6']: rule.set_v6(True) self.rules6.append(rule) else: rule.set_v6(False) self.rules.append(rule) orig.close()