Skip to content
Permalink
Browse files

Merge PR #2879: Various minor fixes in preparation for hot-cert reload

  • Loading branch information...
mkrautz committed Feb 26, 2017
2 parents 85d6239 + 1a0e145 commit 1a1bd8c101210e24d66549a315e6f39b9ec5dc00
@@ -159,17 +159,26 @@ void Server::initializeCert() {
qscCert = Meta::mp.qscCert;
qskKey = Meta::mp.qskKey;
qlIntermediates = Meta::mp.qlIntermediates;

if (!qscCert.isNull() && !qskKey.isNull()) {
bUsingMetaCert = true;
}
}

// If we still don't have a certificate by now, try to load the one from Meta
if (qscCert.isNull() || qskKey.isNull()) {
if (! key.isEmpty() || ! crt.isEmpty()) {
log("Certificate specified, but failed to load.");
}

qskKey = Meta::mp.qskKey;
qscCert = Meta::mp.qscCert;
qlIntermediates = Meta::mp.qlIntermediates;

if (!qscCert.isNull() && !qskKey.isNull()) {
bUsingMetaCert = true;
}

// If loading from Meta doesn't work, build+sign a new one
if (qscCert.isNull() || qskKey.isNull()) {
log("Generating new server certificate.");
@@ -90,11 +90,18 @@ MetaParams::~MetaParams() {
* @param T Conversion target type (type of 'defaultValue', auto inducable)
* @param name qsSettings variable name
* @param defaultValue Default value for 'name'
* @param settings The QSettings object to read from. If null, the Meta's qsSettings will be used.
* @return Setting if valid, default if not or setting not set.
*/
template <class T>
T MetaParams::typeCheckedFromSettings(const QString &name, const T &defaultValue) {
QVariant cfgVariable = qsSettings->value(name, defaultValue);
T MetaParams::typeCheckedFromSettings(const QString &name, const T &defaultValue, QSettings *settings) {
// Use qsSettings unless a specific QSettings instance
// is requested.
if (settings == NULL) {
settings = qsSettings;
}

QVariant cfgVariable = settings->value(name, defaultValue);

if (!cfgVariable.convert(QVariant(defaultValue).type())) { // Bit convoluted as canConvert<T>() only does a static check without considering whether say a string like "blub" is actually a valid double (which convert does).
qCritical() << "Configuration variable" << name << "is of invalid format. Set to default value of" << defaultValue << ".";
@@ -105,6 +112,8 @@ T MetaParams::typeCheckedFromSettings(const QString &name, const T &defaultValue
}

void MetaParams::read(QString fname) {
qmConfig.clear();

if (fname.isEmpty()) {
QStringList datapaths;

@@ -144,27 +153,27 @@ void MetaParams::read(QString fname) {
QFileInfo fi(p, "murmur.ini");
if (fi.exists() && fi.isReadable()) {
qdBasePath = QDir(p);
fname = fi.absoluteFilePath();
qsAbsSettingsFilePath = fi.absoluteFilePath();
break;
}
}
}
if (fname.isEmpty()) {
if (qsAbsSettingsFilePath.isEmpty()) {
QDir::root().mkpath(qdBasePath.absolutePath());
qdBasePath = QDir(datapaths.at(0));
fname = qdBasePath.absolutePath() + QLatin1String("/murmur.ini");
qsAbsSettingsFilePath = qdBasePath.absolutePath() + QLatin1String("/murmur.ini");
}
} else {
QFile f(fname);
if (! f.open(QIODevice::ReadOnly)) {
qFatal("Specified ini file %s could not be opened", qPrintable(fname));
}
qdBasePath = QFileInfo(f).absoluteDir();
fname = QFileInfo(f).absoluteFilePath();
qsAbsSettingsFilePath = QFileInfo(f).absoluteFilePath();
f.close();
}
QDir::setCurrent(qdBasePath.absolutePath());
qsSettings = new QSettings(fname, QSettings::IniFormat);
qsSettings = new QSettings(qsAbsSettingsFilePath, QSettings::IniFormat);
#if QT_VERSION >= 0x040500
qsSettings->setIniCodec("UTF-8");
#endif
@@ -458,49 +467,44 @@ void MetaParams::read(QString fname) {
}
#endif

if (! QSslSocket::supportsSsl()) {
qFatal("Qt without SSL Support");
}

{
QList<QSslCipher> ciphers = MumbleSSL::ciphersFromOpenSSLCipherString(qsCiphers);
if (ciphers.isEmpty()) {
qFatal("Invalid sslCiphers option. Either the cipher string is invalid or none of the ciphers are available: \"%s\"", qPrintable(qsCiphers));
}

#if !defined(USE_QSSLDIFFIEHELLMANPARAMETERS)
// If the version of Qt we're building against doesn't support
// QSslDiffieHellmanParameters, then we must filter out Diffie-
// Hellman cipher suites in order to guarantee that we do not
// use Qt's default Diffie-Hellman parameters.
QList<QSslCipher> filtered;
#if !defined(USE_QSSLDIFFIEHELLMANPARAMETERS)
foreach (QSslCipher c, ciphers) {
if (c.keyExchangeMethod() == QLatin1String("DH")) {
continue;
{
QList<QSslCipher> filtered;
foreach (QSslCipher c, ciphers) {
if (c.keyExchangeMethod() == QLatin1String("DH")) {
continue;
}
filtered << c;
}
filtered << c;
}
if (ciphers.size() != filtered.size()) {
qWarning("Warning: all cipher suites in sslCiphers using Diffie-Hellman key exchange "
"have been removed. Qt %s does not support custom Diffie-Hellman parameters.",
qVersion());
if (ciphers.size() != filtered.size()) {
qWarning("Warning: all cipher suites in sslCiphers using Diffie-Hellman key exchange "
"have been removed. Qt %s does not support custom Diffie-Hellman parameters.",
qVersion());
}

qlCiphers = filtered;
}
#else
filtered = ciphers;
qlCiphers = ciphers;
#endif

QSslSocket::setDefaultCiphers(filtered);

QStringList pref;
foreach (QSslCipher c, filtered) {
foreach (QSslCipher c, qlCiphers) {
pref << c.name();
}
qWarning("Meta: TLS cipher preference is \"%s\"", qPrintable(pref.join(QLatin1String(":"))));
}

qWarning("OpenSSL: %s", SSLeay_version(SSLEAY_VERSION));

qmConfig.clear();
QStringList hosts;
foreach(const QHostAddress &qha, qlBind) {
hosts << qha.toString();
@@ -109,6 +109,10 @@ class MetaParams {
/// sslCA option.
QList<QSslCertificate> qlCA;

/// qlCiphers contains the list of supported
/// cipher suites.
QList<QSslCipher> qlCiphers;

QByteArray qbaDHParams;
QByteArray qbaPassPhrase;
QString qsCiphers;
@@ -125,6 +129,9 @@ class MetaParams {
QVariant qvSuggestPositional;
QVariant qvSuggestPushToTalk;

/// qsAbsSettingsFilePath is the absolute path to
/// the murmur.ini used by this Meta instance.
QString qsAbsSettingsFilePath;
QSettings *qsSettings;

MetaParams();
@@ -133,7 +140,7 @@ class MetaParams {

private:
template <class T>
T typeCheckedFromSettings(const QString &name, const T &variable);
T typeCheckedFromSettings(const QString &name, const T &variable, QSettings *settings = NULL);
};

class Meta : public QObject {
@@ -104,6 +104,8 @@ void Server::update() {
calist << qscCert;
ssl.setCaCertificates(calist);

ssl.setCiphers(Meta::mp.qlCiphers);

qnr.setSslConfiguration(ssl);

QNetworkReply *rep = qnamNetwork->post(qnr, doc.toString().toUtf8());
@@ -100,6 +100,7 @@ Server::Server(int snum, QObject *p) : QThread(p) {
#ifdef USE_BONJOUR
bsRegistration = NULL;
#endif
bUsingMetaCert = false;

#ifdef Q_OS_UNIX
aiNotify[0] = aiNotify[1] = -1;
@@ -1213,6 +1214,8 @@ void Server::newClient() {
// bundle used for this server's certificate.
sock->addCaCertificates(qlIntermediates);

sock->setCiphers(Meta::mp.qlCiphers);

#if defined(USE_QSSLDIFFIEHELLMANPARAMETERS)
QSslConfiguration cfg = sock->sslConfiguration();
cfg.setDiffieHellmanParameters(qsdhpDHParams);
@@ -131,6 +131,7 @@ class Server : public QThread {
QVariant qvSuggestPositional;
QVariant qvSuggestPushToTalk;

bool bUsingMetaCert;
QSslCertificate qscCert;
QSslKey qskKey;

@@ -85,6 +85,7 @@ extern QFile *qfLog;

int UnixMurmur::iHupFd[2];
int UnixMurmur::iTermFd[2];
int UnixMurmur::iUsr1Fd[2];

UnixMurmur::UnixMurmur() {
bRoot = true;
@@ -99,13 +100,18 @@ UnixMurmur::UnixMurmur() {
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, iTermFd))
qFatal("Couldn't create TERM socketpair");

if (::socketpair(AF_UNIX, SOCK_STREAM, 0, iUsr1Fd))
qFatal("Couldn't create USR1 socketpair");

qsnHup = new QSocketNotifier(iHupFd[1], QSocketNotifier::Read, this);
qsnTerm = new QSocketNotifier(iTermFd[1], QSocketNotifier::Read, this);
qsnUsr1 = new QSocketNotifier(iUsr1Fd[1], QSocketNotifier::Read, this);

connect(qsnHup, SIGNAL(activated(int)), this, SLOT(handleSigHup()));
connect(qsnTerm, SIGNAL(activated(int)), this, SLOT(handleSigTerm()));
connect(qsnUsr1, SIGNAL(activated(int)), this, SLOT(handleSigUsr1()));

struct sigaction hup, term;
struct sigaction hup, term, usr1;

hup.sa_handler = hupSignalHandler;
sigemptyset(&hup.sa_mask);
@@ -121,20 +127,31 @@ UnixMurmur::UnixMurmur() {
if (sigaction(SIGTERM, &term, NULL))
qFatal("Failed to install SIGTERM handler");

usr1.sa_handler = usr1SignalHandler;
sigemptyset(&usr1.sa_mask);
usr1.sa_flags = SA_RESTART;

if (sigaction(SIGUSR1, &usr1, NULL))
qFatal("Failed to install SIGUSR1 handler");

umask(S_IRWXO);
}

UnixMurmur::~UnixMurmur() {
delete qsnHup;
delete qsnTerm;
delete qsnUsr1;

qsnHup = NULL;
qsnTerm = NULL;
qsnUsr1 = NULL;

close(iHupFd[0]);
close(iHupFd[1]);
close(iTermFd[0]);
close(iTermFd[1]);
close(iUsr1Fd[0]);
close(iUsr1Fd[1]);
}

void UnixMurmur::hupSignalHandler(int) {
@@ -149,6 +166,12 @@ void UnixMurmur::termSignalHandler(int) {
Q_UNUSED(len);
}

void UnixMurmur::usr1SignalHandler(int) {
char a = 1;
ssize_t len = ::write(iUsr1Fd[0], &a, sizeof(a));
Q_UNUSED(len);
}


// Keep these two synchronized with matching actions in DBus.cpp

@@ -199,6 +222,17 @@ void UnixMurmur::handleSigTerm() {
qsnTerm->setEnabled(true);
}

void UnixMurmur::handleSigUsr1() {
qsnUsr1->setEnabled(false);
char tmp;
ssize_t len = ::read(iUsr1Fd[1], &tmp, sizeof(tmp));
Q_UNUSED(len);

qWarning("Received USR1 signal... Ignoring...");

qsnUsr1->setEnabled(true);
}

void UnixMurmur::setuid() {
if (Meta::mp.uiUid != 0) {
#ifdef Q_OS_DARWIN
@@ -32,14 +32,16 @@ class UnixMurmur : public QObject {
Q_DISABLE_COPY(UnixMurmur)
protected:
bool bRoot;
static int iHupFd[2], iTermFd[2];
QSocketNotifier *qsnHup, *qsnTerm;
static int iHupFd[2], iTermFd[2], iUsr1Fd[2];
QSocketNotifier *qsnHup, *qsnTerm, *qsnUsr1;

static void hupSignalHandler(int);
static void termSignalHandler(int);
static void usr1SignalHandler(int);
public slots:
void handleSigHup();
void handleSigTerm();
void handleSigUsr1();
public:
bool logToSyslog;

@@ -365,6 +365,12 @@ int main(int argc, char **argv) {
}
}

if (QSslSocket::supportsSsl()) {
qWarning("SSL: OpenSSL version is '%s'", SSLeay_version(SSLEAY_VERSION));
} else {
qFatal("SSL: this version of Murmur is built against Qt without SSL Support. Aborting.");
}

#ifdef Q_OS_UNIX
inifile = unixhandler.trySystemIniFiles(inifile);
#endif

0 comments on commit 1a1bd8c

Please sign in to comment.
You can’t perform that action at this time.