File indexing completed on 2025-01-05 05:07:02
0001 // SPDX-License-Identifier: GPL-2.0-or-later 0002 // SPDX-FileCopyrightText: 2020 Lucas Biaggi <lbjanuario@gmail.com> 0003 /* 0004 * Firewalld backend for plasma firewall 0005 */ 0006 0007 #include <QDBusConnection> 0008 #include <QDBusMessage> 0009 #include <QDBusPendingCall> 0010 #include <QDBusPendingReply> 0011 #include <QDebug> 0012 #include <QRegularExpression> 0013 0014 #include <KLocalizedString> 0015 0016 #include "firewalldjob.h" 0017 0018 Q_LOGGING_CATEGORY(FirewallDJobDebug, "firewalld.job") 0019 0020 namespace FIREWALLD 0021 { 0022 const QString BUS = QStringLiteral("org.fedoraproject.FirewallD1"); 0023 const QString PATH = QStringLiteral("/org/fedoraproject/FirewallD1"); 0024 } 0025 0026 namespace DIRECT 0027 { 0028 const QString KCM_FIREWALLD_DIR = QStringLiteral("/etc/kcm/firewalld"); 0029 const QString LOG_FILE = QStringLiteral("/var/log/firewalld.log"); 0030 const QString INTERFACE = QStringLiteral("org.fedoraproject.FirewallD1.direct"); 0031 } 0032 0033 namespace SAVE 0034 { 0035 const QString METHOD = QStringLiteral("runtimeToPermanent"); 0036 } 0037 0038 namespace SERVICES 0039 { 0040 const QString INTERFACE = QStringLiteral("org.fedoraproject.FirewallD1"); 0041 const QString METHOD = QStringLiteral("listServices"); 0042 } 0043 0044 namespace SIMPLE 0045 { 0046 const QString INTERFACE = QStringLiteral("org.fedoraproject.FirewallD1.zone"); 0047 } 0048 0049 namespace AUTH 0050 { 0051 const QString METHOD = QStringLiteral("authorizeAll"); 0052 } 0053 0054 enum { 0055 DBUSFIREWALLDDERROR = KJob::UserDefinedError, 0056 }; 0057 0058 FirewalldJob::FirewalldJob(){}; 0059 0060 FirewalldJob::FirewalldJob(const QByteArray &call, const QVariantList &args, const FirewalldJob::JobType &type) 0061 : KJob() 0062 , m_type(type) 0063 , m_call(call) 0064 , m_args(args){}; 0065 0066 FirewalldJob::FirewalldJob(const FirewalldJob::JobType &type) 0067 : KJob() 0068 , m_type(type){}; 0069 0070 template<typename T> 0071 T FirewalldJob::connectCall(QDBusPendingCallWatcher *watcher) 0072 { 0073 QDBusPendingReply<T> reply = *watcher; 0074 if (reply.isError()) { 0075 setErrorText(reply.error().message()); 0076 setError(DBUSFIREWALLDDERROR); 0077 qCDebug(FirewallDJobDebug) << "job error message: " << errorString(); 0078 emitResult(); 0079 } 0080 return reply.value(); 0081 } 0082 0083 void FirewalldJob::connectCall(QDBusPendingCallWatcher *watcher) 0084 { 0085 QDBusPendingReply<> reply = *watcher; 0086 if (reply.isError()) { 0087 setErrorText(reply.error().message()); 0088 setError(DBUSFIREWALLDDERROR); 0089 qCDebug(FirewallDJobDebug) << "job error message: " << errorString(); 0090 emitResult(); 0091 } 0092 } 0093 0094 void FirewalldJob::firewalldAction(const QString &bus, const QString &path, const QString &interface, const QString &method, const QVariantList &args) 0095 { 0096 QDBusMessage call = QDBusMessage::createMethodCall(bus, path, interface, method); 0097 call.setArguments(args); 0098 QDBusPendingCall message = QDBusConnection::systemBus().asyncCall(call); 0099 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(message, this); 0100 if (args.isEmpty()) { 0101 connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, interface, method](QDBusPendingCallWatcher *watcher) { 0102 watcher->deleteLater(); 0103 if (interface == DIRECT::INTERFACE) { // iptables rules like 0104 QList<firewalld_reply> reply = connectCall<QList<firewalld_reply>>(watcher); 0105 if (!reply.isEmpty()) { 0106 m_firewalldreply = reply; 0107 } 0108 } else if (interface == SERVICES::INTERFACE && method != SAVE::METHOD 0109 && method != AUTH::METHOD) { // list services available or enabled services AND don't execute runtimeToPermanent HERE 0110 QStringList reply = connectCall<QStringList>(watcher); 0111 if (!reply.isEmpty()) { 0112 m_services = reply; 0113 } 0114 0115 } else { 0116 connectCall(watcher); // save executed here 0117 } 0118 emitResult(); 0119 return; 0120 }); 0121 0122 } else { 0123 connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, interface, method](QDBusPendingCallWatcher *watcher) { 0124 watcher->deleteLater(); 0125 if (interface == SIMPLE::INTERFACE) { // believe or not to get the data from active zone you need to send "" 0126 if (method.contains(QRegularExpression("^(add|remove)"))) { 0127 QString reply = connectCall<QString>(watcher); 0128 if (!reply.isEmpty()) 0129 qCDebug(FirewallDJobDebug) << "manipulated zone: " << reply; 0130 0131 } else if (method == "getZoneSettings2") { 0132 QMap<QString, QVariant> settings; 0133 settings = connectCall<QMap<QString, QVariant>>(watcher); 0134 m_target = settings["target"].toString(); 0135 } else { 0136 QStringList reply = connectCall<QStringList>(watcher); 0137 if (!reply.isEmpty()) { 0138 m_services = reply; 0139 } 0140 } 0141 } else { 0142 connectCall(watcher); 0143 } 0144 emitResult(); 0145 return; 0146 }); 0147 } 0148 } 0149 0150 QList<firewalld_reply> FirewalldJob::getFirewalldreply() const 0151 { 0152 return m_firewalldreply; 0153 } 0154 0155 FirewalldJob::~FirewalldJob() = default; 0156 0157 void FirewalldJob::start() 0158 { 0159 switch (m_type) { 0160 case FirewalldJob::SIMPLIFIEDRULE: 0161 case FirewalldJob::SIMPLELIST: { 0162 qCDebug(FirewallDJobDebug) << "firewalld zone interface: " << m_call << m_args; 0163 firewalldAction(FIREWALLD::BUS, FIREWALLD::PATH, SIMPLE::INTERFACE, m_call, m_args); 0164 break; 0165 } 0166 case FirewalldJob::FIREWALLD: { 0167 qCDebug(FirewallDJobDebug) << "firewalld direct: " << m_call << m_args; 0168 /* firewalldAction(m_call, m_args); */ 0169 firewalldAction(FIREWALLD::BUS, FIREWALLD::PATH, DIRECT::INTERFACE, m_call, m_args); 0170 break; 0171 } 0172 case FirewalldJob::SAVEFIREWALLD: { 0173 qCDebug(FirewallDJobDebug) << i18n("firewalld saving (runtime to permanent)"); 0174 firewalldAction(FIREWALLD::BUS, FIREWALLD::PATH, SERVICES::INTERFACE, SAVE::METHOD); 0175 /* saveFirewalld(); */ 0176 break; 0177 } 0178 case FirewalldJob::LISTSERVICES: { 0179 /* listServices(); */ 0180 firewalldAction(FIREWALLD::BUS, FIREWALLD::PATH, SERVICES::INTERFACE, SERVICES::METHOD); 0181 break; 0182 } 0183 case FirewalldJob::ALL: { 0184 firewalldAction(FIREWALLD::BUS, FIREWALLD::PATH, SERVICES::INTERFACE, AUTH::METHOD); 0185 break; 0186 } 0187 0188 default: 0189 emitResult(); 0190 return; 0191 } 0192 return; 0193 }; 0194 0195 QString FirewalldJob::name() const 0196 { 0197 return m_type == FirewalldJob::SAVEFIREWALLD ? i18n("firewalld saving") : i18n("firewalld %1").arg(QString(m_call)); 0198 } 0199 0200 QStringList FirewalldJob::getServices() const 0201 { 0202 return m_services; 0203 } 0204 0205 QString FirewalldJob::getDefaultIncomingPolicy() const 0206 { 0207 return m_target; 0208 }