File indexing completed on 2024-04-28 16:52:16
0001 // SPDX-License-Identifier: GPL-2.0-or-later 0002 // SPDX-FileCopyrightText: 2011 Craig Drummond <craig.p.drummond@gmail.com> 0003 // SPDX-FileCopyrightText: 2018 Alexis Lopes Zubeta <contact@azubieta.net> 0004 // SPDX-FileCopyrightText: 2020 Tomaz Canabrava <tcanabrava@kde.org> 0005 /* 0006 * UFW KControl Module 0007 */ 0008 0009 #include "profile.h" 0010 #include "firewallclient.h" 0011 0012 #include <QBuffer> 0013 #include <QFile> 0014 #include <QIODevice> 0015 #include <QStringList> 0016 #include <QTextStream> 0017 #include <QXmlStreamReader> 0018 0019 Profile::Profile(QByteArray &xml, bool isSys) 0020 : m_fields(0) 0021 , m_enabled(false) 0022 , m_ipv6Enabled(false) 0023 , m_logLevel(Types::LOG_OFF) 0024 , m_defaultIncomingPolicy(Types::POLICY_ALLOW) 0025 , m_defaultOutgoingPolicy(Types::POLICY_ALLOW) 0026 , m_isSystem(isSys) 0027 { 0028 QBuffer buffer; 0029 buffer.setBuffer(&xml); 0030 load(&buffer); 0031 } 0032 0033 Profile::Profile(QFile &file, bool isSys) 0034 : m_fields(0) 0035 , m_enabled(false) 0036 , m_ipv6Enabled(false) 0037 , m_logLevel(Types::LOG_OFF) 0038 , m_defaultIncomingPolicy(Types::POLICY_ALLOW) 0039 , m_defaultOutgoingPolicy(Types::POLICY_ALLOW) 0040 , m_fileName(file.fileName()) 0041 , m_isSystem(isSys) 0042 { 0043 load(&file); 0044 } 0045 0046 Profile::Profile(const QVector<Rule *> &rules, const QVariantMap &args, bool isSys) 0047 : m_fields(0) 0048 , m_enabled(false) 0049 , m_ipv6Enabled(false) 0050 , m_logLevel(Types::LOG_OFF) 0051 , m_defaultIncomingPolicy(Types::POLICY_ALLOW) 0052 , m_defaultOutgoingPolicy(Types::POLICY_ALLOW) 0053 , m_isSystem(isSys) 0054 { 0055 setRules(rules); 0056 setArgs(args); 0057 } 0058 0059 void Profile::setRules(const QVector<Rule *> &newrules) 0060 { 0061 m_rules = newrules; 0062 } 0063 0064 void Profile::setArgs(const QVariantMap &args) 0065 { 0066 const QString new_defaultIncomingPolicy = args.value(QStringLiteral("defaultIncomingPolicy")).toString(); 0067 const QString new_defaultOutgoingPolicy = args.value(QStringLiteral("defaultIncomingPolicy")).toString(); 0068 const QString new_loglevel = args.value(QStringLiteral("logLevel")).toString(); 0069 const QStringList new_modules = args.value(QStringLiteral("modules")).toStringList(); 0070 0071 m_defaultIncomingPolicy = new_defaultIncomingPolicy.isEmpty() ? Types::POLICY_ALLOW : Types::toPolicy(new_defaultIncomingPolicy); 0072 m_defaultOutgoingPolicy = new_defaultOutgoingPolicy.isEmpty() ? Types::POLICY_ALLOW : Types::toPolicy(new_defaultOutgoingPolicy); 0073 m_logLevel = new_loglevel.isEmpty() ? Types::LOG_OFF : Types::toLogLevel(new_loglevel); 0074 m_enabled = args.value(QStringLiteral("status")).toBool(); 0075 m_ipv6Enabled = args.value("ipv6Enabled").toBool(); 0076 0077 if (!new_modules.isEmpty()) { 0078 m_modules = QSet<QString>(std::begin(new_modules), std::end(new_modules)); 0079 } 0080 } 0081 0082 void Profile::setDefaultIncomingPolicy(const QString &policy) 0083 { 0084 m_defaultIncomingPolicy = Types::toPolicy(policy); 0085 } 0086 0087 void Profile::setDefaultOutgoingPolicy(const QString &policy) 0088 { 0089 m_defaultOutgoingPolicy = Types::toPolicy(policy); 0090 } 0091 0092 QString Profile::toXml() const 0093 { 0094 QString str; 0095 QTextStream stream(&str); 0096 0097 stream << "<ufw full=\"true\" >" << Qt::endl << ' ' << defaultsXml() << Qt::endl << " <rules>" << Qt::endl; 0098 0099 /* for (const auto &rule : m_rules) { */ 0100 /* stream << " " << rule->toXml(); */ 0101 /* } */ 0102 0103 stream << " </rules>" << Qt::endl << ' ' << modulesXml() << Qt::endl << "</ufw>" << Qt::endl; 0104 0105 return str; 0106 } 0107 0108 QString Profile::defaultsXml() const 0109 { 0110 static const auto defaultString = QStringLiteral(R"(<defaults ipv6="%1" loglevel="%2" incoming="%3" outgoing="%4"/>)"); 0111 0112 return defaultString.arg(m_ipv6Enabled ? "yes" : "no") 0113 .arg(Types::toString(m_logLevel)) 0114 .arg(Types::toString(m_defaultIncomingPolicy)) 0115 .arg(Types::toString(m_defaultOutgoingPolicy)); 0116 } 0117 0118 QString Profile::modulesXml() const 0119 { 0120 return QString("<modules enabled=\"") + QStringList(m_modules.values()).join(" ") + QString("\" />"); 0121 } 0122 0123 void Profile::load(QIODevice *device) 0124 { 0125 device->open(QIODevice::ReadOnly); 0126 QXmlStreamReader reader(device); 0127 0128 bool isFullProfile = false; 0129 while (!reader.atEnd()) { 0130 auto token = reader.readNext(); 0131 if (token == QXmlStreamReader::Invalid) { 0132 break; 0133 } 0134 if (token != QXmlStreamReader::StartElement) { 0135 continue; 0136 } 0137 if (reader.name() == QStringLiteral("ufw")) { 0138 isFullProfile = reader.attributes().value(QStringLiteral("full")) == QStringLiteral("true"); 0139 continue; 0140 } else if (reader.name() == QStringLiteral("status")) { 0141 m_enabled = reader.attributes().value(QStringLiteral("enabled")) == QStringLiteral("true"); 0142 m_fields |= FIELD_STATUS; 0143 } else if (reader.name() == QStringLiteral("rules")) { 0144 m_fields |= FIELD_RULES; 0145 continue; 0146 } else if (reader.name() == QLatin1String("rule")) { 0147 static QString ANY_ADDR = QStringLiteral("0.0.0.0/0"); 0148 static QString ANY_ADDR_V6 = QStringLiteral("::/0"); 0149 static QString ANY_PORT = QStringLiteral("any"); 0150 0151 const auto attr = reader.attributes(); 0152 0153 // Handle Enums. 0154 const auto action = Types::toPolicy(attr.value(QLatin1String("action")).toString()); 0155 0156 // TODO: Check that this is ok. 0157 const auto protocol = FirewallClient::indexOfProtocol(attr.value(QLatin1String("protocol")).toString()); 0158 /* qDebug() << "Reading protocol from profile:" << protocol << attr.value(QLatin1String("protocol")); */ 0159 0160 const auto logType = Types::toLogging(attr.value(QLatin1String("logtype")).toString()); 0161 0162 // Handle values that have weird defaults. 0163 const auto anyAddrs = QList<QString>({ANY_ADDR, ANY_ADDR_V6}); 0164 const auto dst = attr.value("dst").toString(); 0165 const auto src = attr.value("src").toString(); 0166 const auto sport = attr.value("sport").toString(); 0167 const auto dport = attr.value("dport").toString(); 0168 0169 const QString destAddress = anyAddrs.contains(dst) ? QString() : dst; 0170 const QString sourceAddress = anyAddrs.contains(src) ? QString() : src; 0171 const QString sourcePort = sport == ANY_PORT ? QString() : sport; 0172 const QString destPort = dport == ANY_PORT ? QString() : dport; 0173 0174 m_rules.append(new Rule(action, 0175 attr.value("direction") == QStringLiteral("in"), 0176 logType, 0177 protocol, 0178 sourceAddress, 0179 sourcePort, 0180 destAddress, 0181 destPort, 0182 attr.value("interface_in").toString(), 0183 attr.value("interface_out").toString(), 0184 attr.value("sapp").toString(), 0185 attr.value("dapp").toString(), 0186 attr.value("position").toInt(), 0187 attr.value("v6") == QStringLiteral("True"))); 0188 } else if (reader.name() == QLatin1String("defaults")) { 0189 m_fields |= FIELD_DEFAULTS; 0190 0191 const auto attr = reader.attributes(); 0192 0193 m_logLevel = Types::toLogLevel(attr.value(QLatin1String("loglevel")).toString()); 0194 0195 m_defaultIncomingPolicy = Types::toPolicy(attr.value(QLatin1String("incoming")).toString()); 0196 m_defaultOutgoingPolicy = Types::toPolicy(attr.value(QLatin1String("outgoing")).toString()); 0197 0198 m_ipv6Enabled = (attr.value("ipv6") == QLatin1String("yes")); 0199 } else if (reader.name() == QLatin1String("modules")) { 0200 m_fields |= FIELD_MODULES; 0201 const auto attr = reader.attributes(); 0202 const auto moduleList = attr.value("enabled").toString().split(" ", Qt::SkipEmptyParts); 0203 m_modules = QSet<QString>(std::begin(moduleList), std::end(moduleList)); 0204 } 0205 } 0206 if (isFullProfile && (!(m_fields & FIELD_RULES) || !(m_fields & FIELD_DEFAULTS) || !(m_fields & FIELD_MODULES))) { 0207 m_fields = 0; 0208 } 0209 } 0210 0211 void Profile::setEnabled(bool value) 0212 { 0213 m_enabled = value; 0214 }