1 /***************************************************************************
2 * Copyright (C) 2005-2020 by the Quassel Project *
3 * devel@quassel-irc.org *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
20
21 #ifdef HAVE_UMASK
22 # include <sys/stat.h>
23 # include <sys/types.h>
24 #endif /* HAVE_UMASK */
25
26 #include <QString>
27
28 #include "corenetwork.h"
29 #include "oidentdconfiggenerator.h"
30
OidentdConfigGenerator(QObject * parent)31 OidentdConfigGenerator::OidentdConfigGenerator(QObject* parent)
32 : QObject(parent)
33 {
34 if (!_initialized)
35 init();
36 }
37
~OidentdConfigGenerator()38 OidentdConfigGenerator::~OidentdConfigGenerator()
39 {
40 _quasselConfig.clear();
41 writeConfig();
42 _configFile->deleteLater();
43 }
44
init()45 bool OidentdConfigGenerator::init()
46 {
47 _configDir.setPath(QDir::homePath());
48 _configFileName = ".oidentd.conf";
49
50 if (Quassel::isOptionSet("oidentd-conffile"))
51 _configPath = Quassel::optionValue("oidentd-conffile");
52 else
53 _configPath = _configDir.absoluteFilePath(_configFileName);
54
55 _configTag = " stanza created by Quassel";
56
57 _configFile = new QFile(_configPath);
58
59 // Rx has to match Template in order for cleanup to work.
60 // Template should be enhanced with the "from" parameter as soon as Quassel gains
61 // the ability to bind to an IP on client sockets.
62
63 _quasselStanzaTemplate = QString("lport %1 { reply \"%2\" } #%3\n");
64 _quasselStanzaRx = QRegExp(QString(R"(^lport .* \{ .* \} #%1\r?\n)").arg(_configTag));
65
66 // initially remove all Quassel stanzas that might be present
67 if (parseConfig(false) && writeConfig())
68 _initialized = true;
69
70 return _initialized;
71 }
72
sysIdentForIdentity(const CoreIdentity * identity) const73 QString OidentdConfigGenerator::sysIdentForIdentity(const CoreIdentity* identity) const
74 {
75 // Make sure the identity's ident complies with strict mode if enabled
76 const CoreNetwork* network = qobject_cast<CoreNetwork*>(sender());
77 return network->coreSession()->strictCompliantIdent(identity);
78 }
79
addSocket(const CoreIdentity * identity,const QHostAddress & localAddress,quint16 localPort,const QHostAddress & peerAddress,quint16 peerPort,qint64 socketId)80 bool OidentdConfigGenerator::addSocket(const CoreIdentity* identity,
81 const QHostAddress& localAddress,
82 quint16 localPort,
83 const QHostAddress& peerAddress,
84 quint16 peerPort,
85 qint64 socketId)
86 {
87 Q_UNUSED(localAddress)
88 Q_UNUSED(peerAddress)
89 Q_UNUSED(peerPort)
90 Q_UNUSED(socketId)
91
92 const QString ident = sysIdentForIdentity(identity);
93
94 _quasselConfig.append(_quasselStanzaTemplate.arg(localPort).arg(ident).arg(_configTag).toLatin1());
95
96 bool ret = writeConfig();
97
98 return ret;
99 }
100
101 //! not yet implemented
removeSocket(const CoreIdentity * identity,const QHostAddress & localAddress,quint16 localPort,const QHostAddress & peerAddress,quint16 peerPort,qint64 socketId)102 bool OidentdConfigGenerator::removeSocket(const CoreIdentity* identity,
103 const QHostAddress& localAddress,
104 quint16 localPort,
105 const QHostAddress& peerAddress,
106 quint16 peerPort,
107 qint64 socketId)
108 {
109 Q_UNUSED(identity)
110 Q_UNUSED(localAddress)
111 Q_UNUSED(localPort)
112 Q_UNUSED(peerAddress)
113 Q_UNUSED(peerPort)
114 Q_UNUSED(socketId)
115
116 return true;
117 }
118
parseConfig(bool readQuasselStanzas)119 bool OidentdConfigGenerator::parseConfig(bool readQuasselStanzas)
120 {
121 if (!_configFile->exists())
122 return true;
123
124 if (!_configFile->isOpen() && !_configFile->open(QIODevice::ReadOnly))
125 return false;
126 _mutex.lock();
127
128 _parsedConfig.clear();
129 _configFile->seek(0);
130 while (!_configFile->atEnd()) {
131 QByteArray line = _configFile->readLine();
132
133 if (!lineByUs(line))
134 _parsedConfig.append(line);
135 else if (readQuasselStanzas)
136 _quasselConfig.append(line);
137 }
138
139 _configFile->close();
140 _mutex.unlock();
141 return true;
142 }
143
writeConfig()144 bool OidentdConfigGenerator::writeConfig()
145 {
146 #ifdef HAVE_UMASK
147 mode_t prev_umask = umask(S_IXUSR | S_IWGRP | S_IXGRP | S_IWOTH | S_IXOTH); // == 0133, rw-r--r--
148 #endif
149 bool not_open = (!_configFile->isOpen() && !_configFile->open(QIODevice::ReadWrite | QIODevice::Text));
150 #ifdef HAVE_UMASK
151 umask(prev_umask);
152 #endif
153
154 if (not_open)
155 return false;
156
157 _mutex.lock();
158
159 _configFile->seek(0);
160 _configFile->resize(0);
161 _configFile->write(_parsedConfig);
162 _configFile->write(_quasselConfig);
163
164 _configFile->close();
165 _mutex.unlock();
166 return true;
167 }
168
lineByUs(const QByteArray & line)169 bool OidentdConfigGenerator::lineByUs(const QByteArray& line)
170 {
171 return _quasselStanzaRx.exactMatch(line);
172 }
173